From d8377411663ff4c17d8752e1be1cf94d00f4dc54 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Tue, 9 Sep 2014 11:11:52 +0200 Subject: [PATCH 0001/1152] tests: use nanosleep instead of usleep man usleep says that bahaviour of using usleep with SIGALRM signal is unspecified. So create our own usleep that calls nanosleep instead. Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- tests/display-test.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index 1289866f..451cabd8 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -333,6 +333,21 @@ register_reading(struct wl_display *display) assert(wl_display_flush(display) >= 0); } +#define USEC_TO_NSEC(n) (1000 * (n)) + +/* since we are using alarm() and SIGABRT, we can not + * use usleep function (see 'man usleep') */ +static void +test_usleep(useconds_t usec) +{ + struct timespec ts = { + .tv_sec = 0, + .tv_nsec = USEC_TO_NSEC(usec) + }; + + assert(nanosleep(&ts, NULL) == 0); +} + /* create thread that will call prepare+read so that * it will block */ static pthread_t @@ -349,8 +364,8 @@ create_thread(struct client *c, void *(*func)(void*)) * so call usleep once again after the loop ends - it should * be sufficient... */ while (c->display_stopped == 0) - usleep(500); - usleep(10000); + test_usleep(500); + test_usleep(10000); return thread; } @@ -517,8 +532,8 @@ threading_read_after_error(void) /* make sure thread is sleeping */ while (c->display_stopped == 0) - usleep(500); - usleep(10000); + test_usleep(500); + test_usleep(10000); assert(wl_display_read_events(c->wl_display) == -1); From 65d02b7a83329ab5a65a0effde854baf8d5d2040 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 10 Sep 2014 12:47:12 +0200 Subject: [PATCH 0002/1152] display-test: test if threads are woken up on EAGAIN When wl_connection_read() in wl_display_read_events() returns with EAGAIN, we want the sleeping threads to be woken up. Test it! Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- tests/display-test.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index 451cabd8..a1e45b1c 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -495,6 +495,45 @@ TEST(threading_cancel_read_tst) display_destroy(d); } +static void +threading_read_eagain(void) +{ + struct client *c = client_connect(); + pthread_t th1, th2, th3; + + register_reading(c->wl_display); + + th1 = create_thread(c, thread_prepare_and_read); + th2 = create_thread(c, thread_prepare_and_read); + th3 = create_thread(c, thread_prepare_and_read); + + /* All the threads are sleeping, waiting until read or cancel + * is called. Since we have no data on socket waiting, + * the wl_connection_read should end up with error and set errno + * to EAGAIN. Check if the threads are woken up in this case. */ + assert(wl_display_read_events(c->wl_display) == 0); + /* errno should be still set to EAGAIN if wl_connection_read + * set it - check if we're testing the right case */ + assert(errno == EAGAIN); + + alarm(3); + pthread_join(th1, NULL); + pthread_join(th2, NULL); + pthread_join(th3, NULL); + + client_disconnect(c); +} + +TEST(threading_read_eagain_tst) +{ + struct display *d = display_create(); + client_create(d, threading_read_eagain); + + display_run(d); + + display_destroy(d); +} + static void * thread_prepare_and_read2(void *data) { From a31a7360093dd5f4ce1a34b9889560fc37dbb7a9 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 10 Sep 2014 12:47:13 +0200 Subject: [PATCH 0003/1152] client: wake-up threads on all return paths from read_events If wl_connection_read returned EAGAIN, we must wake up sleeping threads. If we don't do this and the thread calling wl_connection_read won't call wl_display_read_events again, the sleeping threads will sleep indefinitely. Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- src/wayland-client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 9f817f69..1b7a0466 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1152,8 +1152,13 @@ read_events(struct wl_display *display) if (display->reader_count == 0) { total = wl_connection_read(display->connection); if (total == -1) { - if (errno == EAGAIN) + if (errno == EAGAIN) { + /* we must wake up threads whenever + * the reader_count dropped to 0 */ + display_wakeup_threads(display); + return 0; + } display_fatal_error(display, errno); return -1; From 083d8da432b2052db78f0a19405275c2b4391b5a Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 10 Sep 2014 12:47:14 +0200 Subject: [PATCH 0004/1152] client: cancel read in wl_display_read_events() when last_error is set Calling wl_display_read_events() after an error should be equivalent to wl_display_cancel_read(), so that display state is consistent. Thanks to Pekka Paalanen for pointing that out. Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- src/wayland-client.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 1b7a0466..b0f77b9e 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1192,6 +1192,14 @@ read_events(struct wl_display *display) return 0; } +static void +cancel_read(struct wl_display *display) +{ + display->reader_count--; + if (display->reader_count == 0) + display_wakeup_threads(display); +} + /** Read events from display file descriptor * * \param display The display context object @@ -1219,6 +1227,7 @@ wl_display_read_events(struct wl_display *display) pthread_mutex_lock(&display->mutex); if (display->last_error) { + cancel_read(display); pthread_mutex_unlock(&display->mutex); errno = display->last_error; @@ -1365,9 +1374,7 @@ wl_display_cancel_read(struct wl_display *display) { pthread_mutex_lock(&display->mutex); - display->reader_count--; - if (display->reader_count == 0) - display_wakeup_threads(display); + cancel_read(display); pthread_mutex_unlock(&display->mutex); } From 4d7dfa0867d7661c86b717998ea96a0f2987cee2 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 10 Sep 2014 13:46:09 -0500 Subject: [PATCH 0005/1152] shm: fix error in comment --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 3fce678e..04ba4f26 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -372,7 +372,7 @@ wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer) * Returns a pointer which can be used to read the data contained in * the given SHM buffer. * - * As this buffer is memory-mapped, reading it from may generate + * As this buffer is memory-mapped, reading from it may generate * SIGBUS signals. This can happen if the client claims that the * buffer is larger than it is or if something truncates the * underlying file. To prevent this signal from causing the compositor From edf4e7abea4046f003f53c300acf9af7dffc2e48 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 12 Sep 2014 12:26:50 +0300 Subject: [PATCH 0006/1152] configure.ac: bump version to 1.5.93 for rc2 Signed-off-by: Pekka Paalanen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5deed2be..c556d4fc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [5]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 339e83aa579569711cd14623ca4b2db46256b766 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 19 Sep 2014 12:36:04 +0300 Subject: [PATCH 0007/1152] configure.ac: bump version to 1.6.0 Signed-off-by: Pekka Paalanen --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c556d4fc..cc7b5355 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [5]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [6]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 472f0c48e667ff13794bc86750f6c74baabdc284 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 22 Sep 2014 09:51:20 +0300 Subject: [PATCH 0008/1152] configure.ac: bump version to 1.6.90 Master is open for new features again. Signed-off-by: Pekka Paalanen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cc7b5355..df1f92da 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [6]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From f3e7eedf1c0824639a816519ccfbdacb946cc63f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Sep 2014 17:32:10 +1000 Subject: [PATCH 0009/1152] doc: replace publican with xmlto Publican isn't packaged for some distros, xmlto is a lot more common. Most of what publican provides for us is the stylesheet anyway, so we can just use xmlto and the publican stylesheet to get roughly the same look. PDF and XML generation has been dropped, this needs a bit more more effort than a mere switchover to xmlto. The top-level directory structure imposed by publican is kept for now (specifically the Wayland/en-US/html tree). This makes it easier to transition over for packagers. Note that the list of files inside has changed. CSS files are taken from publican to keep a uniform look compared to previous documentations. Stylesheets are licensed under CC0 1.0 Universal license, see publican/LICENSE: 1. Files in the datadir/Common_Content directory and its subdirectories are licensed under the CC0 1.0 Universal license. To the extent possible under law, the developers of Publican waive all copyright and related or neighboring rights to the files contained in the datadir/Common_Content directory and its subdirectories. Acked-by: Pekka Paalanen --- configure.ac | 12 +- doc/publican/Makefile.am | 70 +- doc/publican/publican.cfg | 9 - doc/publican/sources/css/brand.css | 14 + doc/publican/sources/css/common.css | 1769 ++++++++++++++++++++++++++ doc/publican/sources/css/default.css | 3 + doc/publican/sources/css/epub.css | 115 ++ doc/publican/sources/css/print.css | 15 + 8 files changed, 1956 insertions(+), 51 deletions(-) delete mode 100644 doc/publican/publican.cfg create mode 100644 doc/publican/sources/css/brand.css create mode 100644 doc/publican/sources/css/common.css create mode 100644 doc/publican/sources/css/default.css create mode 100644 doc/publican/sources/css/epub.css create mode 100644 doc/publican/sources/css/print.css diff --git a/configure.ac b/configure.ac index df1f92da..6f8220bd 100644 --- a/configure.ac +++ b/configure.ac @@ -109,14 +109,10 @@ if test "x$enable_documentation" = "xyes"; then AC_MSG_ERROR([Documentation build requested but doxygen not found. Install doxygen or disable the documentation using --disable-documentation]) fi - AC_PATH_PROG(PUBLICAN, publican) + AC_PATH_PROG(XMLTO, xmlto) - if test "x$PUBLICAN" != "x"; then - PUBLICAN_VERSION=[`$PUBLICAN -v | sed -e 's/version=v\?\([0-9]*\.[0-9]*\).*/\1/'`] - - if test [ 1 -eq `echo "${PUBLICAN_VERSION} < 2.8" | bc` ]; then - AC_MSG_ERROR([Publican version is not supported. Install publican >= 2.8 or disable the documentation using --disable-documentation]) - fi + if test "x$XMLTO" = "x"; then + AC_MSG_ERROR([Documentation build requested but xmlto not found. Install xmlto or disable the documentation using --disable-documentation]) fi AC_CONFIG_FILES([ @@ -124,7 +120,7 @@ if test "x$enable_documentation" = "xyes"; then ]) fi -AM_CONDITIONAL([HAVE_PUBLICAN], [test "x$PUBLICAN" != "x"]) +AM_CONDITIONAL([HAVE_XMLTO], [test "x$XMLTO" != "x"]) AC_CONFIG_FILES([Makefile cursor/wayland-cursor.pc diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 47fc66d2..cf0f533f 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -1,14 +1,10 @@ -# Documentation is built with publican -# https://fedorahosted.org/publican/ -# Publican takes docbook-style input files and compiles them to various -# output formats. +# Documentation is built with xmlto, but some of the recipes in here are +# leftovers from building with Publican (https://fedorahosted.org/publican/) # # How this build works: # * the main target is Wayland, documentation ends up in $(builddir)/Wayland/ -# * hand-written chapters are located in sources -# Publican does not take a source path, so to support out-of-tree builds -# these are copied to $(builddir)/en-US which is the actual directory -# Publican uses. +# * hand-written chapters and CSS files are located in sources. These are +# copied into $(builddir)/en-US/ # * ProtocolSpec.xml is generated from $(top_srcdir)/protocol/wayland.xml, # changed into docbook via XSLT and saved in $(builddir)/en-US/ # * ProtocolInterfaces.xml, same as above, uses a different XSLT @@ -16,7 +12,7 @@ # $(builddir)/en-US # * WaylandServerAPI.xml is generated from the doxygen output and saved in # $(builddir)/en-US -# * run Publican on en-US +# * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US publican_sources = \ $(srcdir)/sources/Wayland.ent \ $(srcdir)/sources/Wayland.xml \ @@ -35,9 +31,36 @@ publican_sources = \ $(srcdir)/sources/images/wayland.png \ $(srcdir)/sources/images/x-architecture.png -if HAVE_PUBLICAN +css_sources = \ + $(srcdir)/sources/css/brand.css \ + $(srcdir)/sources/css/common.css \ + $(srcdir)/sources/css/default.css \ + $(srcdir)/sources/css/epub.css \ + $(srcdir)/sources/css/print.css +img_sources = \ + $(srcdir)/sources/images/icon.svg \ + $(srcdir)/sources/images/wayland-architecture.png \ + $(srcdir)/sources/images/wayland.png \ + $(srcdir)/sources/images/x-architecture.png + +if HAVE_XMLTO if HAVE_XSLTPROC noinst_DATA = Wayland $(publican_targets) +XMLTO_PARAM = \ + --stringparam chunk.section.depth=0 \ + --stringparam toc.section.depth=1 \ + --stringparam html.stylesheet=css/default.css + +html_destdir = $(builddir)/Wayland/en-US/html + +Wayland: $(publican_targets) + $(AM_V_GEN)$(MKDIR_P) -p $(html_destdir)/css + $(AM_V_GEN)cp -f $(css_sources) $(html_destdir)/css/ + $(AM_V_GEN)$(MKDIR_P) -p $(html_destdir)/images + $(AM_V_GEN)cp -f $(img_sources) $(html_destdir)/images/ + $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html en-US/Wayland.xml -o $(html_destdir) + @touch Wayland + pubdir = $(docdir)/Wayland/en-US publican_targets = $(publican_sources:$(srcdir)/sources%=$(builddir)/en-US%) \ @@ -85,37 +108,16 @@ $(builddir)/en-US/%: $(srcdir)/sources/% en-US/ProtocolSpec.xml en-US/ProtocolIn $(AM_V_GEN)cp -f $< $@ $(AM_V_GEN)chmod a+w $@ -# Run publican for the builddir on the generated (or copied) source -# The output formats are generated in the Wayland sub directory. Also, we need -# to use a tmp publican.cfg cause 'publican rename' modifies the original. -Wayland: $(publican_targets) - $(AM_V_GEN)cp -f $(srcdir)/publican.cfg $(builddir)/publican-copy.cfg - $(AM_V_GEN)$(PUBLICAN) rename --name Wayland \ - --version "$(WAYLAND_VERSION_MAJOR).$(WAYLAND_VERSION_MINOR)" \ - --config $(builddir)/publican-copy.cfg - $(AM_V_GEN)$(PUBLICAN) build --quiet --langs en-US --pdftool fop --formats html,pdf \ - --config $(builddir)/publican-copy.cfg - @touch Wayland - CLEANFILES = en-US/ProtocolSpec.xml en-US/ProtocolInterfaces.xml en-US/WaylandClientAPI.xml $(publican_targets) clean-local: $(AM_V_at)rm -fr $(builddir)/en-US $(AM_V_at)rm -fr $(builddir)/Wayland - $(AM_V_at)rm -fr $(builddir)/publican-copy.cfg install-data-local: - test -z "$(pubdir)/html/Common_Content/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/Common_Content/css" - test -z "$(pubdir)/html/Common_Content/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/Common_Content/images" + test -z "$(pubdir)/html/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/css" test -z "$(pubdir)/html/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/images" - test -z "$(pubdir)/html-pdf/Common_Content/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html-pdf/Common_Content/css" - test -z "$(pubdir)/html-pdf/Common_Content/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html-pdf/Common_Content/images" - test -z "$(pubdir)/html-pdf/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html-pdf/images" - test -z "$(pubdir)/pdf" || $(mkdir_p) "$(DESTDIR)$(pubdir)/pdf" - test -z "$(pubdir)/xml/Common_Content/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/xml/Common_Content/css" - test -z "$(pubdir)/xml/Common_Content/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/xml/Common_Content/images" - test -z "$(pubdir)/xml/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/xml/images" - list=`find $(builddir)/Wayland/en-US -type f -not -path '$(builddir)/Wayland/en-US/xml_tmp*'`; \ + list=`find $(builddir)/Wayland/en-US -type f`; \ for p in $$list; do \ echo " $(INSTALL_DATA) '$$p' '$(DESTDIR)$(docdir)/$$p'"; \ $(INSTALL_DATA) "$$p" "$(DESTDIR)$(docdir)/$$p"; \ @@ -132,4 +134,4 @@ uninstall-local: endif endif -EXTRA_DIST = $(publican_sources) publican.cfg protocol-to-docbook.xsl protocol-interfaces-to-docbook.xsl doxygen-to-publican.xsl +EXTRA_DIST = $(publican_sources) $(css_sources) $(img_sources) protocol-to-docbook.xsl protocol-interfaces-to-docbook.xsl doxygen-to-publican.xsl diff --git a/doc/publican/publican.cfg b/doc/publican/publican.cfg deleted file mode 100644 index ccb9f04f..00000000 --- a/doc/publican/publican.cfg +++ /dev/null @@ -1,9 +0,0 @@ -# Config::Simple 4.59 -# Fri Feb 24 09:36:50 2012 - -xml_lang: "en-US" -type: Book -brand: common -tmp_dir: Wayland -toc_section_depth: 1 -chunk_section_depth: 0 diff --git a/doc/publican/sources/css/brand.css b/doc/publican/sources/css/brand.css new file mode 100644 index 00000000..d86cba93 --- /dev/null +++ b/doc/publican/sources/css/brand.css @@ -0,0 +1,14 @@ +/*headings*/ +h1, h2, h3, h4, h5, h6, +div.producttitle, +div.subtitle, +div.author div.author, +div.translator div.translator, +div.othercredit div.othercredit, +div.editor div.editor, +div.contrib div.contrib, +.title, +.titlepage .edition, +.titlepage .releaseinfo { + color: #336699; +} diff --git a/doc/publican/sources/css/common.css b/doc/publican/sources/css/common.css new file mode 100644 index 00000000..a05648ef --- /dev/null +++ b/doc/publican/sources/css/common.css @@ -0,0 +1,1769 @@ +* { + widows: 4 !important; + orphans: 4 !important; +} + +body, h1, h2, h3, h4, h5, h6, pre, li, div { + line-height: 1.29em; +} + +body { + background-color: white; + margin:0 auto; + font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif; + font-size: 14px; + max-width: 770px; + color: black; +} + +body.toc_embeded { + /*for web hosting system only*/ + margin-left: 300px; +} + +object.toc, iframe.toc { + /*for web hosting system only*/ + border-style: none; + position: fixed; + width: 290px; + height: 99.99%; + top: 0; + left: 0; + z-index: 100; + border-style: none; + border-right:1px solid #999; +} + +/* Hide web menu */ + +body.notoc { + margin-left: 3em; +} + +iframe.notoc { + border-style:none; + border: none; + padding: 0px; + position:fixed; + width: 21px; + height: 29px; + top: 0px; + left:0; + overflow: hidden; + margin: 0px; + margin-left: -3px; +} +/* End hide web menu */ + +/* desktop styles */ +body.desktop { + margin-left: 26em; +} + +body.desktop .book > .toc { + display:block; + width:24em; + height:99.99%; + position:fixed; + overflow:auto; + top:0px; + left:0px; +/* padding-left:1em; */ + background-color:#EEEEEE; + font-size: 12px; +} + +body.pdf { + max-width: 100%; +} + +.toc { + line-height:1.35em; +} + +.toc .glossary, +.toc .chapter, .toc .appendix { + margin-top:1em; +} + +.toc .part { + margin-top:1em; + display:block; +} + +span.glossary, +span.appendix { + display:block; + margin-top:0.5em; +} + +div { + padding-top:0px; +} + +div.section { + page-break-inside: avoid; +} + +p, div.para { + padding-top: 0px; + margin-top: 1em; + padding-bottom: 0px; + margin-bottom: 1em; +} + +div.formalpara { + padding-top: 0px; + margin-top: 1em; + padding-bottom: 0px; + margin-bottom: 1em; +} + +.varlistentry div.para { + page-break-before: avoid; + +} + +/*Links*/ +a { + outline: none; +} + +a:link { + text-decoration: none; + border-bottom: 1px dotted ; + color:#3366cc; +} + +body.pdf a:link { + word-wrap: break-word; +} + +a:visited { + text-decoration:none; + border-bottom: 1px dotted ; + color:#003366; +} + +div.longdesc-link { + float:right; + color:#999; +} + +.toc a, .qandaset a { + font-weight:normal; + border:none; +} + +.toc a:hover, .qandaset a:hover +{ + border-bottom: 1px dotted; +} + +/*headings*/ +h1, h2, h3, h4, h5, h6 { + color: #336699; + margin-top: 0px; + margin-bottom: 0px; + background-color: transparent; + margin-bottom: 0px; + margin-top: 20px; + page-break-inside: avoid; + page-break-after: avoid; + word-wrap: break-word; +} + +h1 { + font-size: 22px; +} + +.titlepage h1.title { + text-align:left; +} + +.book > .titlepage h1.title { + text-align: center; +} + +.article > .titlepage h1.title, +.article > .titlepage h2.title { + text-align: center; +} + +.set .titlepage > div > div > h1.title { + text-align: center; +} + +.part > .titlepage h1.title { + text-align: center; + font-size: 24px; +} + +div.producttitle { + margin-top: 0px; + margin-bottom: 20px; + font-size: 48px; + font-weight: bold; +/* background: #003d6e url(../images/h1-bg.png) top left repeat-x; */ + color: #336699; + text-align: center; + padding-top: 12px; +} + +.titlepage .corpauthor { + margin-top: 1em; + text-align: center; +} + +.section h1.title { + font-size: 18px; + padding: 0px; + color: #336699; + text-align: left; + background: white; +} + +h2 { + font-size: 20px; + margin-top: 30px; +} + + +.book div.subtitle, .book h2.subtitle, .book h3.subtitle { + margin-top: 1em; + margin-bottom: 1em; + font-size: 18px; + text-align: center; +} + +div.subtitle { + color: #336699; + font-weight: bold; +} + +h1.legalnotice { + font-size: 24px; +} + +.preface > div > div > div > h2.title, +.preface > div > div > div > h1.title { + margin-top: 1em; + font-size: 24px; +} + +.appendix h2 { + font-size: 24px; +} + + + +h3 { + font-size: 14px; + padding-top:0px; + padding-bottom: 0px; + margin-bottom: 0px; +} +h4 { + font-size: 14px; + padding-top:0px; + padding-bottom:0px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 14px; + margin-bottom: 0px; +} + +.abstract h6 { + margin-top:1em; + margin-bottom:.5em; + font-size: 24px; +} + +.index > div > div > div > h2.title { + font-size: 24px; +} + +.chapter > div > div > div > h2.title { + font-size: 24px; +} + +.section > div > div > div > h2.title { + font-size: 21px; + page-break-inside: avoid; + page-break-before: avoid; + page-break-after: avoid; +} + +.section > div > div > div > h3.title { + font-size: 17px; +} + +/*element rules*/ +hr { + border-collapse: collapse; + border-style:none; + border-top: 1px dotted #ccc; + width:100%; +} + +/* web site rules */ +ul.languages, .languages li { + display:inline; + padding:0px; +} + +.languages li a { + padding:0px .5em; + text-decoration: none; +} + +.languages li p, .languages li div.para { + display:inline; +} + +.languages li a:link, .languages li a:visited { + color:#444; +} + +.languages li a:hover, .languages li a:focus, .languages li a:active { + color:black; +} + +ul.languages { + display:block; + background-color:#eee; + padding:.5em; +} + +/*supporting stylesheets*/ + +/*unique to the webpage only*/ +.books { + position:relative; +} + +.versions li { + width:100%; + clear:both; + display:block; +} + +a.version { + font-size: 20px; + text-decoration:none; + width:100%; + display:block; + padding:1em 0px .2em 0px; + clear:both; +} + +a.version:before { + content:"Version"; + font-size: smaller; +} + +a.version:visited, a.version:link { + color:#666; +} + +a.version:focus, a.version:hover { + color:black; +} + +.books { + display:block; + position:relative; + clear:both; + width:100%; +} + +.books li { + display:block; + width:200px; + float:left; + position:relative; + clear: none ; +} + +.books .html { + width:170px; + display:block; +} + +.books .pdf { + position:absolute; + left:170px; + top:0px; + font-size: smaller; +} + +.books .pdf:link, .books .pdf:visited { + color:#555; +} + +.books .pdf:hover, .books .pdf:focus { + color:#000; +} + +.books li a { + text-decoration:none; +} + +.books li a:hover { + color:black; +} + +/*products*/ +.products li { + display: block; + width:300px; + float:left; +} + +.products li a { + width:300px; + padding:.5em 0px; +} + +.products ul { + clear:both; +} + +/*revision history*/ +.revhistory { + display:block; +} + +.revhistory table { + background-color:transparent; + border-color:#fff; + padding:0px; + margin: 0; + border-collapse:collapse; + border-style:none; +} + +.revhistory td { + text-align :left; + padding:0px; + border: none; + border-top: 1px solid #fff; + font-weight: bold; +} + +.revhistory .simplelist td { + font-weight: normal; +} + +.revhistory .simplelist { + margin-bottom: 1.5em; + margin-left: 1em; +} + +.revhistory table th { + display: none; +} + + +/*credits*/ +.authorgroup div { + clear:both; + text-align: center; +} + +div.author div.author, +div.translator div.translator, +div.othercredit div.othercredit, +div.editor div.editor, +div.contrib div.contrib { + margin: 0px; + padding: 0px; + margin-top: 12px; + font-size: 14px; + font-weight: bold; + color: #336699; +} + +div.editedby { + margin-top: 15px; + margin-bottom: -0.8em; +} + +div.authorgroup .author, +div.authorgroup.editor, +div.authorgroup.translator, +div.authorgroup.othercredit, +div.authorgroup.contrib { + display: block; + font-size: 14px; + page-break-inside: avoid; +} + +.revhistory .author { + display: inline; +} + +.othercredit h3 { + padding-top: 1em; +} + + +.othercredit { + margin:0px; + padding:0px; +} + +.releaseinfo { + clear: both; +} + +.copyright { + margin-top: 1em; +} + +/* qanda sets */ +.answer { + margin-bottom:1em; + border-bottom:1px dotted #ccc; +} + +.qandaset .toc { + border-bottom:1px dotted #ccc; +} + +.question { + font-weight:bold; +} + +.answer .data, .question .data { + padding-left: 2.6em; +} + +.answer .label, .question .label { + float:left; + font-weight:bold; +} + +/* inline syntax highlighting */ +.perl_Alert { + color: #0000ff; +} + +.perl_BaseN { + color: #007f00; +} + +.perl_BString { + color: #5C3566; +} + +.perl_Char { + color: #ff00ff; +} + +.perl_Comment { + color: #888888; +} + + +.perl_DataType { + color: #0000ff; +} + + +.perl_DecVal { + color: #00007f; +} + + +.perl_Error { + color: #ff0000; +} + + +.perl_Float { + color: #00007f; +} + + +.perl_Function { + color: #007f00; +} + + +.perl_IString { + color: #5C3566; +} + + +.perl_Keyword { + color: #002F5D; +} + + +.perl_Operator { + color: #ffa500; +} + + +.perl_Others { + color: #b03060; +} + + +.perl_RegionMarker { + color: #96b9ff; +} + + +.perl_Reserved { + color: #9b30ff; +} + + +.perl_String { + color: #5C3566; +} + + +.perl_Variable { + color: #0000ff; +} + + +.perl_Warning { + color: #0000ff; +} + +/*Lists*/ +ul { + list-style-image: url("../images/dot.png"); + list-style-type: circle; + padding-left: 1.6em; +} + +ul ul { + list-style-image: url("../images/dot2.png"); + list-style-type: circle; +} + +ol.1 { + list-style-type: decimal; +} + +ol.a, +ol ol { + list-style-type: lower-alpha; +} + +ol.i { + list-style-type: lower-roman; +} +ol.A { + list-style-type: upper-alpha; +} + +ol.I { + list-style-type: upper-roman; +} + +dt { + font-weight:bold; + margin-bottom:0px; + padding-bottom:0px; +} + +dd { + margin:0px; + margin-left:2em; + padding-top:0px; +} + +li { + padding-top: 0px; + margin-top: 0px; + padding-bottom: 0px; +/* margin-bottom: 16px; */ +} + +/*images*/ +img { + display:block; + margin: 2em 0; + max-width: 100%; +} + +.inlinemediaobject, +.inlinemediaobject img, +.inlinemediaobject object { + display:inline; + margin:0px; + overflow: hidden; +} + +.figure { + margin-top: 1em; + width: 100%; +} + +.figure img, +.mediaobject img { + display:block; + margin: 0em; + page-break-inside: avoid; +} + +.figure .title { + margin-bottom:2em; + padding:0px; +} + +/*document modes*/ +.confidential { + background-color:#900; + color:White; + padding:.5em .5em; + text-transform:uppercase; + text-align:center; +} + +.longdesc-link { + display:none; +} + +.longdesc { + display:none; +} + +.prompt { + padding:0px .3em; +} + +/*user interface styles*/ +.screen .replaceable { +} + +.guibutton, .guilabel { + font-family: "liberation mono", "bitstream vera mono", "dejavu mono", monospace; + font-weight: bold; +} + +.example { + background-color: #ffffff; + border-left: 3px solid #aaaaaa; + padding-top: 1px; + padding-bottom: 0.1em; + padding-left: 1em; +} + +.equation { + border-left: 3px solid #aaaaaa; + background-color: #ffffff; + padding-top: 1px; + padding-bottom: 0.1em; + padding-left: 1em; +} + +.equation-contents { + margin-left: 4em; +} + +div.title { + margin-bottom: 1em; + font-weight: 14px; + font-weight: bold; + color: #336699; + page-break-inside: avoid; + page-break-after: avoid; + word-wrap: break-word; +} + +.example-contents { + background-color: #ffffff; +} + +.example-contents .para { +/* padding: 10px;*/ +} + +/*terminal/console text*/ +.computeroutput, +.option { + font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; + font-weight:bold; +} + +.replaceable { + font-style: italic; +} + +.command, .filename, .keycap, .classname, .literal { + font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; + font-weight:bold; +} + +/* no bold in toc */ +.toc * { + font-weight: inherit; +} + +.toc H1 { + font-weight: bold; +} + + +div.programlisting { + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ +} + +pre { + font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; + display:block; + background-color: #f5f5f5; + color: #000000; +/* border: 1px solid #aaaaaa; */ + margin-bottom: 1em; + padding:.5em 1em; + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + font-size: 0.9em; + border-style:none; + box-shadow: 0 2px 5px #AAAAAA inset; + -moz-box-shadow: 0 2px 5px #AAAAAA inset; + -webkit-box-shadow: 0 2px 5px #AAAAAA inset; + -o-box-shadow: 0 2px 5px #AAAAAA inset; +} + +body.pdf pre { + border: 1px solid #AAAAAA; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; +} + + +pre .replaceable, +pre .keycap { +} + +code { + font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; + white-space: pre-wrap; + word-wrap: break-word; + font-weight:bold; +} + +.parameter code { + display: inline; + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ +} + +code.email { + font-weight: normal; + font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif; + +} + +/*Notifications*/ +div.warning:before { + content:url(../images/warning.png); + padding-left: 5px; +} + +div.note:before { + content:url(../images/note.png); + padding-left: 5px; +} + +div.important:before { + content:url(../images/important.png); + padding-left: 5px; +} + +div.warning, div.note, div.important { + color: black; + margin: 0px; + padding: 0px; + background: none; + background-color: white; + margin-bottom: 1em; + border-bottom: 1px solid #aaaaaa; + page-break-inside: avoid; +} + +div.admonition_header p { + margin: 0px; + padding: 0px; + color: #eeeeec; + padding-top: 0px; + padding-bottom: 0px; + height: 1.4em; + line-height: 1.4em; + font-size: 17px; + display:inline; +} + +div.admonition_header { + background-origin:content-box; + clear: both; + margin: 0px; + padding: 0px; + margin-top: -40px; + padding-left: 58px; + line-height: 1.0px; + font-size: 1.0px; +} + +div.warning div.admonition_header { + background: url(../images/red.png) top left repeat-x; + background-color: #590000; + background: -webkit-linear-gradient(#a40000,#590000); + background: linear-gradient(#a40000,#590000); +} + +div.note div.admonition_header { + background: url(../images/green.png) top right repeat-x; + background-color: #597800; + background: -webkit-linear-gradient(#769f00,#597800); + background: linear-gradient(#769f00,#597800); +} + +div.important div.admonition_header { + background: url(../images/yellow.png) top right repeat-x; + background-color: #a6710f; + background: -webkit-linear-gradient(#d08e13,#a6710f); + background: linear-gradient(#d08e13,#a6710f); +} + +div.warning p:first-child, +div.warning div.para:first-child, +div.note p:first-child, +div.note div.para:first-child, +div.important p:first-child, +div.important div.para:first-child { + padding: 0px; + margin: 0px; +} + +div.admonition { + border: none; + border-left: 1px solid #aaaaaa; + border-right: 1px solid #aaaaaa; + padding:0px; + margin:0px; + padding-top: 1.5em; + padding-bottom: 1em; + padding-left: 2em; + padding-right: 1em; + background-color: #eeeeec; + -moz-border-radius: 0px; + -webkit-border-radius: 0px; + border-radius: 0px; +} + +/*Page Title*/ +#title { + display:block; + height:45px; + padding-bottom:1em; + margin:0px; +} + +#title a.left{ + display:inline; + border:none; +} + +#title a.left img{ + border:none; + float:left; + margin:0px; + margin-top:.7em; +} + +#title a.right { + padding-bottom:1em; +} + +#title a.right img { + border:none; + float:right; + margin:0px; + margin-top:.7em; +} + +/*Table*/ +div.table { +/* page-break-inside: avoid; */ +} + +table { + border: 1px solid #444; + width:100%; + border-collapse:collapse; + table-layout: fixed; + word-wrap: break-word; +} + +table.blockquote, +table.simplelist, +.calloutlist table { + border-style: none; +} + +table th { + text-align:left; + background-color:#6699cc; + padding:.3em .5em; + color:white; +} + +table td { + padding:.15em .5em; +} + +table tr.even td { + background-color:#f5f5f5; +} + +tr:nth-child(even) { + background-color: #eeeeee; + +} + + +table th p:first-child, table td p:first-child, table li p:first-child, +table th div.para:first-child, table td div.para:first-child, table li div.para:first-child { + margin-top:0px; + padding-top:0px; + display:inline; +} + +th, td { + border-style:none; + vertical-align: top; +/* border: 1px solid #000; */ +} + +.blockquote td, +.simplelist th, +.simplelist td { + border: none; +} + +table table td { + border-bottom:1px dotted #aaa; + background-color:white; + padding:.6em 0px; +} + +table table { + border:1px solid white; +} + +td.remarkval { + color:#444; +} + +td.fieldval { + font-weight:bold; +} + +.lbname, .lbtype, .lbdescr, .lbdriver, .lbhost { + color:white; + font-weight:bold; + background-color:#999; + width:120px; +} + +td.remarkval { + width:230px; +} + +td.tname { + font-weight:bold; +} + +th.dbfield { + width:120px; +} + +th.dbtype { + width:70px; +} + +th.dbdefault { + width:70px; +} + +th.dbnul { + width:70px; +} + +th.dbkey { + width:70px; +} + +span.book { + margin-top:4em; + display:block; + font-size: 11pt; +} + +span.book a{ + font-weight:bold; +} +span.chapter { + display:block; +} + +table.simplelist td, .calloutlist table td { + border-style: none; +} + + +table.lt-4-cols.lt-7-rows td { + border: none; +} +/*to simplify layout*/ + + +table.lt-4-cols.gt-14-rows tr:nth-child(odd) { + background-color: #fafafa; +} +/* to keep simple but stripe rows */ + + +.gt-8-cols td { + border-left: 1px solid #ccc; +} + +.gt-8-cols td:first-child { + border-left: 0; +} +/* to apply vertical lines to differentiate columns*/ + +/*Breadcrumbs*/ +#breadcrumbs ul li.first:before { + content:" "; +} + +#breadcrumbs { + color:#900; + padding:3px; + margin-bottom:25px; +} + +#breadcrumbs ul { + margin-left:0; + padding-left:0; + display:inline; + border:none; +} + +#breadcrumbs ul li { + margin-left:0; + padding-left:2px; + border:none; + list-style:none; + display:inline; +} + +#breadcrumbs ul li:before { + content:"\0020 \0020 \0020 \00BB \0020"; + color:#333; +} + +dl { + margin-top: 0px; + margin-left: 28px; +} + +.toc dl { + margin-left: 10px; +} + +/*index*/ +.glossary h3, +.index h3 { + font-size: 20px; + color:#aaa; + margin:0px; +} + +.indexdiv { + margin-bottom:1em; +} + +.glossary dt, +.index dt { + color:#444; + padding-top:.5em; +} + +.glossary dl dl dt, +.index dl dl dt { + color:#777; + font-weight:normal; + padding-top:0px; +} + +.index dl dl dt:before { + content:"- "; + color:#ccc; +} + +/*changes*/ +.footnote { + font-size: 10px; + margin: 0px; + color: #222; +} + +.footnotes { + margin-bottom: 60px; +} + +table .footnote { +} + +sup { + margin:0px; + padding:0px; + font-size: 10px; + padding-left:0px; +} + +.footnote { + position:relative; +} + +.footnote sup { + color: black; + left: .4em; +} + +.footnote a:link, +.footnote a:visited { + text-decoration:none; + border: none; +} + +.footnote .para sup { +/* position:absolute; */ + vertical-align:text-bottom; +} + +a.footnote { + padding-right: 0.5em; + text-decoration:none; + border: none; +} + +.footnote sup a:link, +.footnote sup a:visited { + color:#92917d; + text-decoration:none; +} + +.footnote:hover sup a { + text-decoration:none; +} + +.footnote p,.footnote div.para { + padding-left:1em; +} + +.footnote a:link, +.footnote a:visited before{ + color:#00537c; +} + +.footnote a:hover { +} + +/**/ +.pdf-break { + page-break-before: always; +} + +div.legalnotice { + page-break-before: always; +} + +div.abstract { + page-break-before: always; +/* page-break-after: always;*/ +} + +div.chapter { + page-break-before: always; +} + + +div.titlepage, div.titlepage > div, div.titlepage > div > div { + page-break-inside: avoid; + page-break-after: avoid; +} + +div.preface, div.part { + page-break-before: always; +} + +div.appendix { + page-break-before: always; +} + +div.section { + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; +} + + +dt.varlistentry { + page-break-inside: avoid; + page-break-after: avoid; +} + +dd { + page-break-before: avoid; +} + +div.note .replaceable, +div.important .replaceable, +div.warning .replaceable, +div.note .keycap, +div.important .keycap, +div.warning .keycap +{ +} + +ul li p:last-child, ul li para:last-child { + margin-bottom:0px; + padding-bottom:0px; +} + +/*document navigation*/ +.docnav a, .docnav strong { + border:none; + text-decoration:none; + font-weight:normal; +} + +.docnav { + list-style:none; + margin:0px; + padding:0px; + position:relative; + width:100%; + padding-bottom:2em; + padding-top:1em; + height:2.5em; + line-height:2.5em; +/* + border-top:1px dotted #ccc; + background-color: rgba(240, 240, 240, 0.9); +-webkitbox-shadow: 0px .15em .5em rgba(0,0,0,0.2); + -moz-box-shadow: 0px .15em .5em rgba(0,0,0,0.2); + box-shadow: 0px .15em .5em rgba(0,0,0,0.2); +*/ +} + +.docnav li { + list-style:none; + margin:0px; + padding:0px; + display:inline; + font-size: 14px; +} + +.docnav li:before { + content:" "; +} + +.docnav li.previous, .docnav li.next { + position:absolute; + top:1.5em; +} + +.docnav li.up, .docnav li.home { + margin:0px 1.5em; +} + +.docnav.top li.home { + color: #336699; + font-size: 22pt; + font-weight: bold; +} + + +.docnav li.previous { + left:0px; + text-align:left; +} + +.docnav li.next { + right:0px; + text-align:right; +} + +.docnav li.previous strong, .docnav li.next strong { + height: 17px; + display: block; +} + +.docnav { + margin:0 auto; + text-align:center; +} + +.docnav li.next a strong { + background: url(../images/stock-go-forward.png) right 120% no-repeat; + padding-top:3px; + padding-bottom:4px; + padding-right:28px; +} + +.docnav li.previous a strong { + background: url(../images/stock-go-back.png) left 120% no-repeat; + padding-top:3px; + padding-bottom:4px; + padding-left:28px; + padding-right:0.5em; +} + +.docnav li.home a strong { + background: url(../images/stock-home.png) top left no-repeat; + padding:5px; + padding-left:28px; +} + +.docnav li.up a strong { + background: url(../images/stock-go-up.png) top left no-repeat; + padding:5px; + padding-left:28px; +} + +.docnav a:link, .docnav a:visited { + color:#666; +} + +.docnav a:hover, .docnav a:focus, .docnav a:active { + color:black; +} + +.docnav a { + max-width: 10px; + overflow:hidden; +} + +.docnav a:link strong { + text-decoration:none; +} + +.docnav { + margin:0 auto; + text-align:center; +} + +ul.docnav { + margin-bottom: 1em; +} +/* Reports */ +.reports ul { + list-style:none; + margin:0px; + padding:0px; +} + +.reports li{ + margin:0px; + padding:0px; +} + +.reports li.odd { + background-color: #eeeeee; + margin:0px; + padding:0px; +} + +.reports dl { + display:inline; + margin:0px; + padding:0px; + float:right; + margin-right: 17em; + margin-top:-1.3em; +} + +.reports dt { + display:inline; + margin:0px; + padding:0px; +} + +.reports dd { + display:inline; + margin:0px; + padding:0px; + padding-right:.5em; +} + +.reports h2, .reports h3{ + display:inline; + padding-right:.5em; + font-size: 14px; + font-weight:normal; +} + +.reports div.progress { + display:inline; + float:right; + width:16em; + background:#c00 url(../images/shine.png) top left repeat-x; + margin:0px; + margin-top:-1.3em; + padding:0px; + border:none; +} + +/*uniform*/ +body.results, body.reports { + max-width:57em ; + padding:0px; +} + +/*Progress Bar*/ +div.progress { + display:block; + float:left; + width:16em; + background:#c00 url(../images/shine.png) top left repeat-x; + height:1em; +} + +div.progress span { + height:1em; + float:left; +} + +div.progress span.translated { + background:#6c3 url(../images/shine.png) top left repeat-x; +} + +div.progress span.fuzzy { + background:#ff9f00 url(../images/shine.png) top left repeat-x; +} + + +/*Results*/ + +.results ul { + list-style:none; + margin:0px; + padding:0px; +} + +.results li{ + margin:0px; + padding:0px; +} + +.results li.odd { + background-color: #eeeeee; + margin:0px; + padding:0px; +} + +.results dl { + display:inline; + margin:0px; + padding:0px; + float:right; + margin-right: 17em; + margin-top:-1.3em; +} + +.results dt { + display:inline; + margin:0px; + padding:0px; +} + +.results dd { + display:inline; + margin:0px; + padding:0px; + padding-right:.5em; +} + +.results h2, .results h3 { + display:inline; + padding-right:.5em; + font-size: 14px; + font-weight:normal; +} + +.results div.progress { + display:inline; + float:right; + width:16em; + background:#c00 url(../images/shine.png) top left repeat-x; + margin:0px; + margin-top:-1.3em; + padding:0px; + border:none; +} + +/* Dirty EVIL Mozilla hack for round corners */ +pre { + -moz-border-radius:11px; + -webkit-border-radius:11px; + border-radius: 11px; +/* page-break-inside: avoid; */ +} + +.example { + -moz-border-radius:0px; + -webkit-border-radius:0px; + border-radius: 0px; + page-break-inside: avoid; +} + +/* move these invisible fields out of the flow */ +.example > a:first-child, +.table > a:first-child { + float: left; +} + +.package, .citetitle { + font-style: italic; +} + +.titlepage .edition, +.titlepage .releaseinfo { + color: #336699; + background-color: transparent; + margin-top: 1em; + margin-bottom: 1em; + font-size: 20px; + font-weight: bold; + text-align: center; +} + +span.remark { + background-color: #ff00ff; +} + +.draft { + background-image: url(../images/watermark-draft.png); + background-repeat: repeat-y; + background-position: center; +} + +.foreignphrase { + font-style: inherit; +} + +dt { + clear:both; + page-break-inside: avoid; + page-break-after: avoid; +} + +dt img { + border-style: none; + max-width: 112px; +} + +dt object { + max-width: 112px; +} + +dt .inlinemediaobject, dt object { + display: inline; + float: left; + margin-bottom: 1em; + padding-right: 1em; + width: 112px; +} + +dl:after { + display: block; + clear: both; + content: ""; +} + +.toc dd { + padding-bottom: 0px; + margin-bottom: 1em; + padding-left: 1.3em; + margin-left: 0px; +} + +div.toc > dl > dt { + padding-bottom: 0px; + margin-bottom: 0px; + margin-top: 1em; +} + + +.strikethrough { + text-decoration: line-through; +} + +.underline { + text-decoration: underline; +} + +.calloutlist img, .callout { + padding: 0px; + margin: 0px; + width: 12pt; + display: inline; + vertical-align: middle; +} + +li.step > a:first-child { + display: block; +} + +.stepalternatives { + list-style-image: none; + list-style-type: upper-alpha; +} +.task { +/* page-break-inside: avoid; */ +} + + +.added { + background-color: #99ff99; +} + +.changed { + background-color: #ffff77; +} + +.deleted { + background-color: #ff4455; + text-decoration: line-through; +} diff --git a/doc/publican/sources/css/default.css b/doc/publican/sources/css/default.css new file mode 100644 index 00000000..bf38ebb5 --- /dev/null +++ b/doc/publican/sources/css/default.css @@ -0,0 +1,3 @@ +@import url("common.css"); +@import url("overrides.css"); +@import url("lang.css"); diff --git a/doc/publican/sources/css/epub.css b/doc/publican/sources/css/epub.css new file mode 100644 index 00000000..b0ffd43c --- /dev/null +++ b/doc/publican/sources/css/epub.css @@ -0,0 +1,115 @@ +/*headings*/ +h1, h2, h3, h4, h5, h6, +div.producttitle, +div.subtitle, +div.author div.author, +div.translator div.translator, +div.othercredit div.othercredit, +div.editor div.editor, +div.contrib div.contrib, +.title, +.titlepage .edition { +} + +div.para { + margin-top: 1em; +} +/* inline syntax highlighting */ +.perl_Alert { + color: #0000ff; +} + +.perl_BaseN { + color: #007f00; +} + +.perl_BString { + color: #5C3566; +} + +.perl_Char { + color: #ff00ff; +} + +.perl_Comment { + color: #888888; +} + + +.perl_DataType { + color: #0000ff; +} + + +.perl_DecVal { + color: #00007f; +} + + +.perl_Error { + color: #ff0000; +} + + +.perl_Float { + color: #00007f; +} + + +.perl_Function { + color: #007f00; +} + + +.perl_IString { + color: #5C3566; +} + + +.perl_Keyword { + color: #002F5D; +} + + +.perl_Operator { + color: #ffa500; +} + + +.perl_Others { + color: #b03060; +} + + +.perl_RegionMarker { + color: #96b9ff; +} + + +.perl_Reserved { + color: #9b30ff; +} + + +.perl_String { + color: #5C3566; +} + + +.perl_Variable { + color: #0000ff; +} + + +.perl_Warning { + color: #0000ff; +} + +b, strong { + font-weight: bolder; +} + +code.command { + font-family: monospace; + font-weight: bolder; +} diff --git a/doc/publican/sources/css/print.css b/doc/publican/sources/css/print.css new file mode 100644 index 00000000..54088f48 --- /dev/null +++ b/doc/publican/sources/css/print.css @@ -0,0 +1,15 @@ +@import url("common.css"); +@import url("overrides.css"); +@import url("lang.css"); + +#tocframe { + display: none; +} + +body.toc_embeded { + margin-left: 30px; +} + +.producttitle { + color: #336699; +} From 2028227acc4fe08836706278698acf1c09851fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 22 Sep 2014 22:11:18 +0200 Subject: [PATCH 0010/1152] scanner: Improve XML parse error reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the parse error and exit with a failure if expat can't parse the XML. Signed-off-by: Jonas Ådahl --- src/scanner.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 72fd3e83..6be1d7ab 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1296,8 +1296,14 @@ int main(int argc, char *argv[]) fprintf(stderr, "fread: %m\n"); exit(EXIT_FAILURE); } - XML_ParseBuffer(ctx.parser, len, len == 0); - + if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) { + fprintf(stderr, + "Error parsing XML at line %ld col %ld: %s\n", + XML_GetCurrentLineNumber(ctx.parser), + XML_GetCurrentColumnNumber(ctx.parser), + XML_ErrorString(XML_GetErrorCode(ctx.parser))); + exit(EXIT_FAILURE); + } } while (len > 0); XML_ParserFree(ctx.parser); From 9dba854547ebdf78276e15003b89f404998c4fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 22 Sep 2014 22:11:19 +0200 Subject: [PATCH 0011/1152] scanner: Remove stray newline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- src/scanner.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 6be1d7ab..809130b1 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -884,7 +884,6 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid desc_dump(mdesc ? mdesc->summary : "(none)", "\t * %s - ", m->name); wl_list_for_each(a, &m->arg_list, link) { - if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL) printf("\t * @interface: name of the objects interface\n" From ff2df60b1a07c3d26d170e65cd5440d15cdf3088 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 18 Aug 2014 17:07:34 +0300 Subject: [PATCH 0012/1152] protocol: define the concept of wl_surface role Define what a role is, and what restrictions there are. A change to existing behaviour is that a role cannot be changed at all once set. However, this is unlikely to cause problems, as there is no reason to re-use wl_surfaces in clients. v2: give more concrete examples of roles, define losing a role, Jasper rewrote the paragraph on how a role is set. v3: make role permanent, there is no such thing as "losing a role". Re-issuing the same role again must be allowed for wl_pointer.set_cursor et al. to work. v4: clarify the semantics of destroying a role object. Signed-off-by: Pekka Paalanen Reviewed-by: Jason Ekstrand --- protocol/wayland.xml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index bb457bcf..621c64d1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -973,8 +973,37 @@ local coordinates of the pixel content, in case a buffer_transform or a buffer_scale is used. - Surfaces are also used for some special purposes, e.g. as - cursor images for pointers, drag icons, etc. + A surface without a "role" is fairly useless, a compositor does + not know where, when or how to present it. The role is the + purpose of a wl_surface. Examples of roles are a cursor for a + pointer (as set by wl_pointer.set_cursor), a drag icon + (wl_data_device.start_drag), a sub-surface + (wl_subcompositor.get_subsurface), and a window as defined by a + shell protocol (e.g. wl_shell.get_shell_surface). + + A surface can have only one role at a time. Initially a + wl_surface does not have a role. Once a wl_surface is given a + role, it is set permanently for the whole lifetime of the + wl_surface object. Giving the current role again is allowed, + unless explicitly forbidden by the relevant interface + specification. + + Surface roles are given by requests in other interfaces such as + wl_pointer.set_cursor. The request should explicitly mention + that this request gives a role to a wl_surface. Often, this + request also creates a new protocol object that represents the + role and adds additional functionality to wl_surface. When a + client wants to destroy a wl_surface, they must destroy this 'role + object' before the wl_surface. + + Destroying the role object does not remove the role from the + wl_surface, but it may stop the wl_surface from "playing the role". + For instance, if a wl_subsurface object is destroyed, the wl_surface + it was created for will be unmapped and forget its position and + z-order. It is allowed to create a wl_subsurface for the same + wl_surface again, but it is not allowed to use the wl_surface as + a cursor (cursor is a different role than sub-surface, and role + switching is not allowed). From a27501f40e9a369ed5d4c655674130e76214281f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 21 Aug 2014 12:32:56 +0300 Subject: [PATCH 0013/1152] protocol: wl_pointer.set_cursor gives a role Now that we have defined "role", use the term. Signed-off-by: Pekka Paalanen Reviewed-by: Jason Ekstrand --- protocol/wayland.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 621c64d1..89f7c0ee 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1394,7 +1394,10 @@ Set the pointer surface, i.e., the surface that contains the - pointer image (cursor). This request only takes effect if the pointer + pointer image (cursor). This request gives the surface the role + of a cursor. + + The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is From 58743c29f8a766657affbf6c277ab108b0385e08 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 21 Aug 2014 12:38:18 +0300 Subject: [PATCH 0014/1152] protocol: wl_data_device.start_drag may give a role Now that we have defined "role", use the term. Signed-off-by: Pekka Paalanen Reviewed-by: Jason Ekstrand --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 89f7c0ee..71293ddc 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -545,7 +545,8 @@ the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.attach request can move the relative position. Attach requests must be confirmed with - wl_surface.commit as usual. + wl_surface.commit as usual. The icon surface is given the role of + a drag-and-drop icon. The current and pending input regions of the icon wl_surface are cleared, and wl_surface.set_input_region is ignored until the From 96fdcfaec7c6617a77cd2d00ffc02b4476575d28 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 21 Aug 2014 12:42:50 +0300 Subject: [PATCH 0015/1152] protocol: wl_subcompositor.get_subsurface gives a role Reword the conditions to make use of the definition of "role". It is still forbidden to create more than one wl_subsurface for a wl_surface at a time. Signed-off-by: Pekka Paalanen Reviewed-by: Jason Ekstrand --- protocol/wayland.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 71293ddc..ddf94a34 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1944,9 +1944,9 @@ associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. - The to-be sub-surface must not already have a dedicated - purpose, like any shell surface type, cursor image, drag icon, - or sub-surface. Otherwise a protocol error is raised. + The to-be sub-surface must not already have another role, and it + must not have an existing wl_subsurface object. Otherwise a protocol + error is raised. Date: Thu, 21 Aug 2014 12:50:50 +0300 Subject: [PATCH 0016/1152] protocol: wl_shell.get_shell_surface gives a role Now that we have defined "role", use the term. Signed-off-by: Pekka Paalanen Reviewed-by: Jason Ekstrand --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index ddf94a34..3645208f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -679,7 +679,8 @@ - Create a shell surface for an existing surface. + Create a shell surface for an existing surface. This gives + the wl_surface the role of a shell surface. Only one shell surface can be associated with a given surface. From 7a0b86ab22e026387b6d529a46d8eb416caa26fa Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 1 Oct 2014 12:52:22 +0300 Subject: [PATCH 0017/1152] protocol: define error codes for role reassignment On the interfaces where it was missing: - wl_data_device - wl_shell - wl_pointer add an error code for requests that set a wl_surface role when the wl_surface already has a different role. This is needed for compositors to appropriately report wl_surface role violations. Signed-off-by: Pekka Paalanen Reviewed-by: Jasper St. Pierre Acked-by: Jason Ekstrand --- protocol/wayland.xml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3645208f..762482e7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -525,6 +525,11 @@ A wl_data_device provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. + + + + + This request asks the compositor to start a drag-and-drop @@ -546,7 +551,8 @@ hotspot, but subsequent wl_surface.attach request can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of - a drag-and-drop icon. + a drag-and-drop icon. If the icon surface already has another role, + it raises a protocol error. The current and pending input regions of the icon wl_surface are cleared, and wl_surface.set_input_region is ignored until the @@ -677,10 +683,15 @@ a basic surface. + + + + Create a shell surface for an existing surface. This gives - the wl_surface the role of a shell surface. + the wl_surface the role of a shell surface. If the wl_surface + already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface. @@ -1393,11 +1404,16 @@ and scrolling. + + + + Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role - of a cursor. + of a cursor. If the surface already has another role, it raises + a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces From 37ffae316431d0afaa8687f355bb175093d736aa Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Wed, 8 Oct 2014 12:20:08 +0100 Subject: [PATCH 0018/1152] README: Tiny cosmetic change --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index ca26cc06..63ffa31d 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -What is Wayland +What is Wayland? Wayland is a project to define a protocol for a compositor to talk to its clients as well as a library implementation of the protocol. The From 5b353ad44d15d416a78b0bcea9114cb3c27f7a6e Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Mon, 29 Sep 2014 17:26:11 +0200 Subject: [PATCH 0019/1152] doc: Mark up some code examples These blocks were misformatted in normal paragraph style in the generated docs. Also, added \comment{} for comments within one code example. Signed-off-by: Benjamin Herr --- src/wayland-util.h | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index fd32826d..05e50ddd 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -89,27 +89,31 @@ struct wl_interface { * * The following code will initialize a list: * - * struct wl_list foo_list; + * ~~~ + * struct wl_list foo_list; * - * struct item_t { - * int foo; - * struct wl_list link; - * }; - * struct item_t item1, item2, item3; + * struct item_t { + * int foo; + * struct wl_list link; + * }; + * struct item_t item1, item2, item3; * - * wl_list_init(&foo_list); - * wl_list_insert(&foo_list, &item1.link); Pushes item1 at the head - * wl_list_insert(&foo_list, &item2.link); Pushes item2 at the head - * wl_list_insert(&item2.link, &item3.link); Pushes item3 after item2 + * wl_list_init(&foo_list); + * wl_list_insert(&foo_list, &item1.link); \comment{Pushes item1 at the head} + * wl_list_insert(&foo_list, &item2.link); \comment{Pushes item2 at the head} + * wl_list_insert(&item2.link, &item3.link); \comment{Pushes item3 after item2} + * ~~~ * * The list now looks like [item2, item3, item1] * * Will iterate the list in ascending order: * - * item_t *item; - * wl_list_for_each(item, foo_list, link) { - * Do_something_with_item(item); - * } + * \code + * item_t *item; + * wl_list_for_each(item, foo_list, link) { + * Do_something_with_item(item); + * } + * \endcode */ struct wl_list { struct wl_list *prev; From 6b511090c5d9ec9116538c9a6cc97a7487bbca75 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Mon, 29 Sep 2014 17:26:12 +0200 Subject: [PATCH 0020/1152] doc: Mostly use apply-templates over value-of xsl:value-of would strip all the nested markup of the selected doxygen elements, so that \ref, \sa and \code formatting didn't actually work. Signed-off-by: Benjamin Herr --- doc/publican/doxygen-to-publican.xsl | 30 +++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 2bd677e7..8ef56143 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -42,11 +42,11 @@ - + - + @@ -61,7 +61,7 @@ - + @@ -70,7 +70,7 @@ Returns: - + @@ -83,7 +83,7 @@ See also: - + @@ -94,18 +94,18 @@ - Since: + Since: - Note: + Note: - + + + + + This request destroys the data device. + + - + The wl_data_device_manager is a singleton global object that provides access to inter-client data transfer mechanisms such as From cb00e27039d3b1b4475150b2468066adb99984dc Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Mon, 3 Nov 2014 09:49:03 +0000 Subject: [PATCH 0025/1152] connection: Fix sendmsg() on FreeBSD It expects ((msg_controllen == 0) == (msg_control == NULL)), and returns EINVAL otherwise. It can't hurt to be tidy about things on other platforms either though. See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=99356#c5 Signed-off-by: Philip Withnall Signed-off-by: Karsten Otto Reviewed-by: Pekka Paalanen --- src/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index c5daca61..f9f24745 100644 --- a/src/connection.c +++ b/src/connection.c @@ -290,7 +290,7 @@ wl_connection_flush(struct wl_connection *connection) msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; - msg.msg_control = cmsg; + msg.msg_control = (clen > 0) ? cmsg : NULL; msg.msg_controllen = clen; msg.msg_flags = 0; From b096693bef569ce463b5444ce654e62293978f8c Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Sat, 1 Nov 2014 17:06:38 +0000 Subject: [PATCH 0026/1152] event-loop.c: Use correct OS abstraction function for dupfd() Signed-off-by: Philip Withnall Signed-off-by: Karsten Otto Reviewed-by: David Fort Reviewed-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- src/event-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index a149db92..1f571ba4 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -134,7 +134,7 @@ wl_event_loop_add_fd(struct wl_event_loop *loop, return NULL; source->base.interface = &fd_source_interface; - source->base.fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); + source->base.fd = wl_os_dupfd_cloexec(fd, 0); source->func = func; source->fd = fd; From a434b7ba8e1fb2f639736b79f6bff668256060b8 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Sat, 1 Nov 2014 17:06:29 +0000 Subject: [PATCH 0027/1152] wayland-server: Abort if a read from a client gives 0 length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This happens on EOF if using a poll function such as select() or kqueue() which doesn’t distinguish EOF events. Currently execution should never reach the point where recvmsg() returns EOF (len == 0). Instead, epoll() will detect this and indicate EPOLLHUP, which is handled a few lines above, closing the connection. However, other event mechanisms may not be able to distinguish EOF from regular readability (in the case of select()) or inconsistently across platforms (in the case of POLLHUP). There is also the possibility of half-closed connections (shutdown(), POLLRDHUP), though this may not be an issue with Wayland. This will not cause problems if the FD polls as readable but actually is not — in that case, recvmsg() will return EAGAIN. Signed-off-by: Philip Withnall Signed-off-by: Karsten Otto Reviewed-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 7caeb302..77755088 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -260,7 +260,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) len = 0; if (mask & WL_EVENT_READABLE) { len = wl_connection_read(connection); - if (len < 0 && errno != EAGAIN) { + if (len == 0 || (len < 0 && errno != EAGAIN)) { wl_client_destroy(client); return 1; } From 2097414a7c8febf89305e1945f51d7fa9972c41f Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Sat, 1 Nov 2014 17:06:46 +0000 Subject: [PATCH 0028/1152] queue-test: Add another assertion Ensure that the round trip succeeds. Signed-off-by: Philip Withnall Signed-off-by: Karsten Otto Reviewed-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- tests/queue-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/queue-test.c b/tests/queue-test.c index 96f21005..6e2e9328 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -66,7 +66,7 @@ client_test_proxy_destroy(void) assert(registry != NULL); wl_registry_add_listener(registry, ®istry_listener, &counter); - wl_display_roundtrip(display); + assert(wl_display_roundtrip(display) != -1); assert(counter == 1); From ba6b79c577e4792f35beb471a8d429475aacf3ad Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 24 Sep 2014 14:07:59 +0200 Subject: [PATCH 0029/1152] tests: use our own XDG_RUNTIME_DIR for tests Use $XDG_RUNTIME_DIR/wayland-tests for tests. This way we won't be messing XDG_RUNTIME_DIR and it also fixes a bug, when socket-test failed when another compositor was running. Signed-off-by: Marek Chalupa Reviewed-by: Giulio Camuffo Reviewed-by: Pekka Paalanen --- tests/test-runner.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/test-runner.c b/tests/test-runner.c index 8f3d5d37..af80d2b2 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -27,10 +27,13 @@ #include #include #include +#include #include #include #include #include +#include + #include "test-runner.h" static int num_alloc; @@ -133,6 +136,45 @@ run_test(const struct test *t) exit(EXIT_SUCCESS); } +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + +static void +set_xdg_runtime_dir(void) +{ + char xdg_runtime_dir[PATH_MAX]; + const char *xrd_env; + + xrd_env = getenv("XDG_RUNTIME_DIR"); + /* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */ + assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests", + xrd_env ? xrd_env : "/tmp") < PATH_MAX) + && "test error: XDG_RUNTIME_DIR too long"); + + if (mkdir(xdg_runtime_dir, 0700) == -1) + if (errno != EEXIST) { + perror("Creating XDG_RUNTIME_DIR"); + abort(); + } + + if (setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1) == -1) { + perror("Setting XDG_RUNTIME_DIR"); + abort(); + } +} + +static void +rmdir_xdg_runtime_dir(void) +{ + const char *xrd_env = getenv("XDG_RUNTIME_DIR"); + assert(xrd_env && "No XDG_RUNTIME_DIR set"); + + /* rmdir may fail if some test didn't do clean up */ + if (rmdir(xrd_env) == -1) + perror("Cleaning XDG_RUNTIME_DIR"); +} + int main(int argc, char *argv[]) { const struct test *t; @@ -158,9 +200,16 @@ int main(int argc, char *argv[]) usage(argv[0], EXIT_FAILURE); } + set_xdg_runtime_dir(); + /* run_test calls exit() */ + assert(atexit(rmdir_xdg_runtime_dir) == 0); + run_test(t); } + /* set our own XDG_RUNTIME_DIR */ + set_xdg_runtime_dir(); + pass = 0; for (t = &__start_test_section; t < &__stop_test_section; t++) { int success = 0; @@ -203,5 +252,8 @@ int main(int argc, char *argv[]) fprintf(stderr, "%d tests, %d pass, %d fail\n", total, pass, total - pass); + /* cleaning */ + rmdir_xdg_runtime_dir(); + return pass == total ? EXIT_SUCCESS : EXIT_FAILURE; } From ff769d8faed7adb6747423a17fbdf11f87b67f64 Mon Sep 17 00:00:00 2001 From: Imran Zaman Date: Wed, 5 Nov 2014 17:40:18 +0200 Subject: [PATCH 0030/1152] scanner, client: Added more error checks when strtol function is used Signed-off-by: Imran Zaman Reviewed-by: Pekka Paalanen --- src/scanner.c | 4 +++- src/wayland-client.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 5e5152ba..fa8e0c0a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -405,11 +405,13 @@ start_element(void *data, const char *element_name, const char **atts) message->destructor = 0; if (since != NULL) { + int prev_errno = errno; errno = 0; version = strtol(since, &end, 0); - if (errno == EINVAL || end == since || *end != '\0') + if (errno != 0 || end == since || *end != '\0') fail(&ctx->loc, "invalid integer (%s)\n", since); + errno = prev_errno; } else { version = 1; } diff --git a/src/wayland-client.c b/src/wayland-client.c index b0f77b9e..01629e01 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -829,9 +829,12 @@ wl_display_connect(const char *name) connection = getenv("WAYLAND_SOCKET"); if (connection) { + int prev_errno = errno; + errno = 0; fd = strtol(connection, &end, 0); - if (*end != '\0') + if (errno != 0 || connection == end || *end != '\0') return NULL; + errno = prev_errno; flags = fcntl(fd, F_GETFD); if (flags != -1) From 94f1718c50588733c639a06e1d3f81228da23eea Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Thu, 30 Oct 2014 00:52:39 -0700 Subject: [PATCH 0031/1152] Don't document an absent parameter. Quells a doxygen warning: src/wayland-server.c:790: warning: argument 'None' of command @param is not found in the argument list of wl_display::wl_display_create(void) Signed-off-by: Bryce Harrington --- src/wayland-server.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 77755088..53ae5ee8 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -787,7 +787,6 @@ bind_display(struct wl_client *client, struct wl_display *display) /** Create Wayland display object. * - * \param None * \return The Wayland display object. Null if failed to create * * This creates the wl_display object. From 754ce18135c778c378bd09b19d9e1e84a5578b07 Mon Sep 17 00:00:00 2001 From: Srivardhan Hebbar Date: Wed, 15 Oct 2014 14:51:27 +0530 Subject: [PATCH 0032/1152] doc: Added API documentation for wl_display_destroy and wl_display_add_socket functions. Signed-off-by: Srivardhan Hebbar [Pekka Paalanen: minor re-wording.] Signed-off-by: Pekka Paalanen --- src/wayland-server.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 53ae5ee8..270e5c70 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -861,6 +861,20 @@ wl_socket_alloc(void) return s; } +/** Destroy Wayland display object. + * + * \param display The Wayland display object which should be destroyed. + * \return None. + * + * This function emits the wl_display destroy signal, releases + * all the sockets added to this display, free's all the globals associated + * with this display, free's memory of additional shared memory formats and + * destroy the display object. + * + * \sa wl_display_add_destroy_listener + * + * \memberof wl_display + */ WL_EXPORT void wl_display_destroy(struct wl_display *display) { @@ -1180,6 +1194,30 @@ wl_display_add_socket_auto(struct wl_display *display) return NULL; } +/** Add a socket to Wayland display for the clients to connect. + * + * \param display Wayland display to which the socket should be added. + * \param name Name of the Unix socket. + * \return 0 if success. -1 if failed. + * + * This adds a Unix socket to Wayland display which can be used by clients to + * connect to Wayland display. + * + * If NULL is passed as name, then it would look for WAYLAND_DISPLAY env + * variable for the socket name. If WAYLAND_DISPLAY is not set, then default + * wayland-0 is used. + * + * The Unix socket will be created in the directory pointed to by environment + * variable XDG_RUNTIME_DIR. If XDG_RUNTIME_DIR is not set, then this function + * fails and returns -1. + * + * The length of socket path, i.e., the path set in XDG_RUNTIME_DIR and the + * socket name, must not exceed the maxium length of a Unix socket path. + * The function also fails if the user do not have write permission in the + * XDG_RUNTIME_DIR path or if the socket name is already in use. + * + * \memberof wl_display + */ WL_EXPORT int wl_display_add_socket(struct wl_display *display, const char *name) { From 9d327c579606cb05928d34bf7a33b2ff581a76fc Mon Sep 17 00:00:00 2001 From: Carlos Olmedo Escobar Date: Wed, 12 Nov 2014 03:19:03 +0100 Subject: [PATCH 0033/1152] Remove useless semicolon. Signed-off-by: Carlos Olmedo Escobar Reviewed-by: Marek Chalupa --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 270e5c70..c40d3001 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1118,7 +1118,7 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name) * "failed to add socket: Success" */ errno = ENAMETOOLONG; return -1; - }; + } return 0; } From 47c752ad82d4475d6f4f605423c93bb29e679bf8 Mon Sep 17 00:00:00 2001 From: Ryo Munakata Date: Wed, 1 Oct 2014 21:17:18 +0900 Subject: [PATCH 0034/1152] connection: abort if a listener function is NULL Signed-off-by: Ryo Munakata Reviewed-by: Pekka Paalanen --- src/connection.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/connection.c b/src/connection.c index f9f24745..25451948 100644 --- a/src/connection.c +++ b/src/connection.c @@ -934,6 +934,11 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags, count + 2, &ffi_type_void, ffi_types); implementation = target->implementation; + if (!implementation[opcode]) { + wl_log("listener function for opcode %u of %s is NULL\n", + opcode, target->interface->name); + abort(); + } ffi_call(&cif, implementation[opcode], NULL, ffi_args); } From 7bf8049c484959f7ccc3262724466172dce786b6 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 12 Nov 2014 13:16:42 +0100 Subject: [PATCH 0035/1152] tests: add timeout Add test_set_timeout() function that allows the test to set timeout for its completition. Any other call to the function re-sets the timeout to the new value. The timeouts can be turned off (usefull when debugging) by setting evironment variable WAYLAND_TESTS_NO_TIMEOUTS. v2: rename NO_TIMEOUTS to WAYLAND_TESTS_NO_TIMEOUTS use unsigned int as argument of test_set_timeout() improve printing of the message about timeout Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- tests/test-runner.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ tests/test-runner.h | 7 +++++++ 2 files changed, 54 insertions(+) diff --git a/tests/test-runner.c b/tests/test-runner.c index af80d2b2..09c50e2d 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -44,6 +44,11 @@ static void* (*sys_calloc)(size_t, size_t); int leak_check_enabled; +/* when this var is set to 0, every call to test_set_timeout() is + * suppressed - handy when debugging the test. Can be set by + * WAYLAND_TESTS_NO_TIMEOUTS evnironment var */ +static int timeouts_enabled = 1; + extern const struct test __start_test_section, __stop_test_section; __attribute__ ((visibility("default"))) void * @@ -110,14 +115,55 @@ usage(const char *name, int status) exit(status); } +void +test_set_timeout(unsigned int to) +{ + int re; + + if (!timeouts_enabled) { + fprintf(stderr, "Timeouts suppressed.\n"); + return; + } + + re = alarm(to); + fprintf(stderr, "Timeout was %sset", re ? "re-" : ""); + + if (to != 0) + fprintf(stderr, " to %d second%c from now.\n", + to, to > 1 ? 's' : 0); + else + fprintf(stderr, " off.\n"); +} + +static void +sigalrm_handler(int signum) +{ + fprintf(stderr, "Test timed out.\n"); + abort(); +} + static void run_test(const struct test *t) { int cur_alloc = num_alloc; int cur_fds, num_fds; + struct sigaction sa; cur_fds = count_open_fds(); + + if (timeouts_enabled) { + sa.sa_handler = sigalrm_handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + assert(sigaction(SIGALRM, &sa, NULL) == 0); + } + t->run(); + + /* turn off timeout (if any) after test completition */ + if (timeouts_enabled) + alarm(0); + if (leak_check_enabled) { if (cur_alloc != num_alloc) { fprintf(stderr, "Memory leak detected in test. " @@ -189,6 +235,7 @@ int main(int argc, char *argv[]) sys_free = dlsym(RTLD_NEXT, "free"); leak_check_enabled = !getenv("NO_ASSERT_LEAK_CHECK"); + timeouts_enabled = !getenv("WAYLAND_TESTS_NO_TIMEOUTS"); if (argc == 2 && strcmp(argv[1], "--help") == 0) usage(argv[0], EXIT_SUCCESS); diff --git a/tests/test-runner.h b/tests/test-runner.h index 707504cc..3295e1cf 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -37,4 +37,11 @@ count_open_fds(void); void exec_fd_leak_check(int nr_expected_fds); /* never returns */ +/* + * set/reset the timeout in seconds. The timeout starts + * at the point of invoking this function + */ +void +test_set_timeout(unsigned int); + #endif From 6ebe55060e6337f56e295032cc776fce694acbdb Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 12 Nov 2014 13:14:46 +0100 Subject: [PATCH 0036/1152] tests: add test_usleep and test_sleep functions The former one was already used in tests, but was private. These functions can be shared across the tests, so make them public. Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- tests/display-test.c | 15 --------------- tests/test-helpers.c | 32 ++++++++++++++++++++++++++++++++ tests/test-runner.h | 12 ++++++++++++ 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index a1e45b1c..f8aac643 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -333,21 +333,6 @@ register_reading(struct wl_display *display) assert(wl_display_flush(display) >= 0); } -#define USEC_TO_NSEC(n) (1000 * (n)) - -/* since we are using alarm() and SIGABRT, we can not - * use usleep function (see 'man usleep') */ -static void -test_usleep(useconds_t usec) -{ - struct timespec ts = { - .tv_sec = 0, - .tv_nsec = USEC_TO_NSEC(usec) - }; - - assert(nanosleep(&ts, NULL) == 0); -} - /* create thread that will call prepare+read so that * it will block */ static pthread_t diff --git a/tests/test-helpers.c b/tests/test-helpers.c index 4761b09e..c05f4b1c 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "test-runner.h" @@ -62,3 +63,34 @@ exec_fd_leak_check(int nr_expected_fds) execl(exe, exe, number, (char *)NULL); assert(0 && "execing fd leak checker failed"); } + +#define USEC_TO_NSEC(n) (1000 * (n)) + +/* our implementation of usleep and sleep functions that are safe to use with + * timeouts (timeouts are implemented using alarm(), so it is not safe use + * usleep and sleep. See man pages of these functions) + */ +void +test_usleep(useconds_t usec) +{ + struct timespec ts = { + .tv_sec = 0, + .tv_nsec = USEC_TO_NSEC(usec) + }; + + assert(nanosleep(&ts, NULL) == 0); +} + +/* we must write the whole function instead of + * wrapping test_usleep, because useconds_t may not + * be able to contain such a big number of microseconds */ +void +test_sleep(unsigned int sec) +{ + struct timespec ts = { + .tv_sec = sec, + .tv_nsec = 0 + }; + + assert(nanosleep(&ts, NULL) == 0); +} diff --git a/tests/test-runner.h b/tests/test-runner.h index 3295e1cf..0e035304 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -5,6 +5,8 @@ #error "Tests must not be built with NDEBUG defined, they rely on assert()." #endif +#include + struct test { const char *name; void (*run)(void); @@ -44,4 +46,14 @@ exec_fd_leak_check(int nr_expected_fds); /* never returns */ void test_set_timeout(unsigned int); +/* test-runner uses alarm() and SIGALRM, so we can not + * use usleep and sleep functions in tests (see 'man usleep' + * or 'man sleep', respectively). Following functions are safe + * to use in tests */ +void +test_usleep(useconds_t); + +void +test_sleep(unsigned int); + #endif From 1d2ef9ee082407b1970c26d0ad799703c2e76aa1 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 12 Nov 2014 13:14:47 +0100 Subject: [PATCH 0037/1152] tests: add timeout tests sanity tests for timeouts. v2: use test_sleep instead of sleep add few more test-cases Signed-off-by: Marek Chalupa Acked-by: Pekka Paalanen --- tests/sanity-test.c | 67 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 46f4f85f..bd3f70ca 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -29,6 +29,9 @@ #include "test-runner.h" #include "wayland-util.h" +#define WL_HIDE_DEPRECATED +#include "test-compositor.h" + extern int leak_check_enabled; TEST(empty) @@ -125,3 +128,67 @@ TEST(sanity_fd_exec) exec_fd_leak_check(nr_fds + 2); } + +FAIL_TEST(timeout_tst) +{ + test_set_timeout(1); + /* test should reach timeout */ + test_sleep(2); +} + +TEST(timeout2_tst) +{ + /* the test should end before reaching timeout, + * thus it should pass */ + test_set_timeout(1); + /* 200 000 microsec = 0.2 sec */ + test_usleep(200000); +} + +FAIL_TEST(timeout_reset_tst) +{ + test_set_timeout(5); + test_set_timeout(10); + test_set_timeout(1); + + /* test should fail on timeout */ + test_sleep(2); +} + +TEST(timeout_turnoff) +{ + test_set_timeout(1); + test_set_timeout(0); + + test_usleep(2); +} + +/* test timeouts with test-compositor */ +FAIL_TEST(tc_timeout_tst) +{ + struct display *d = display_create(); + client_create(d, timeout_tst); + display_run(d); + display_destroy(d); +} + +FAIL_TEST(tc_timeout2_tst) +{ + struct display *d = display_create(); + client_create(d, timeout_reset_tst); + display_run(d); + display_destroy(d); +} + +TEST(tc_timeout3_tst) +{ + struct display *d = display_create(); + + client_create(d, timeout2_tst); + display_run(d); + + client_create(d, timeout_turnoff); + display_run(d); + + display_destroy(d); +} From bbbdff88b1d90cd9f843aab3c06f02dada3741ad Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 24 Sep 2014 14:37:07 +0200 Subject: [PATCH 0038/1152] tests: use test_set_timeout in display-test replace call to alarm() with test_set_timeout() Signed-off-by: Marek Chalupa Acked-by: Giulio Camuffo --- tests/display-test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index f8aac643..aecf3411 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -410,7 +410,7 @@ threading_post_err(void) /* kill test in 3 seconds. This should be enough time for the * thread to exit if it's not blocking. If everything is OK, than * the thread was woken up and the test will end before the SIGALRM */ - alarm(3); + test_set_timeout(3); pthread_join(thread, NULL); wl_proxy_destroy((struct wl_proxy *) c->tc); @@ -462,7 +462,7 @@ threading_cancel_read(void) /* kill test in 3 seconds. This should be enough time for the * thread to exit if it's not blocking. If everything is OK, than * the thread was woken up and the test will end before the SIGALRM */ - alarm(3); + test_set_timeout(3); pthread_join(th1, NULL); pthread_join(th2, NULL); pthread_join(th3, NULL); @@ -501,7 +501,7 @@ threading_read_eagain(void) * set it - check if we're testing the right case */ assert(errno == EAGAIN); - alarm(3); + test_set_timeout(3); pthread_join(th1, NULL); pthread_join(th2, NULL); pthread_join(th3, NULL); @@ -562,7 +562,7 @@ threading_read_after_error(void) assert(wl_display_read_events(c->wl_display) == -1); /* kill test in 3 seconds */ - alarm(3); + test_set_timeout(3); pthread_join(thread, NULL); wl_proxy_destroy((struct wl_proxy *) c->tc); From cf11e9dfbe41d84d537ca11453abbca17170d146 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 24 Sep 2014 14:37:08 +0200 Subject: [PATCH 0039/1152] queue-test: put back timeout In 93e654061b9 we removed call to alarm() that served as timeout in this test. Now when we have test_set_timeout() func, return the timeout back. Signed-off-by: Marek Chalupa Reviewed-by: Giulio Camuffo --- tests/queue-test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/queue-test.c b/tests/queue-test.c index 6e2e9328..d1bf37f9 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -225,6 +225,8 @@ TEST(queue) dummy_interfaces[i]->version, NULL, dummy_bind); + test_set_timeout(2); + client_create(d, client_test_proxy_destroy); display_run(d); From 4d617b83a7cbdb2eefb72796fc971564743e2bc5 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 19 Nov 2014 11:58:26 +0100 Subject: [PATCH 0040/1152] tests: don't print '\0' character print "" (which results in no output) instead of printing '\0' (which is not visible, but is there) Signed-off-by: Marek Chalupa --- tests/test-runner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 09c50e2d..d965a43e 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -129,8 +129,8 @@ test_set_timeout(unsigned int to) fprintf(stderr, "Timeout was %sset", re ? "re-" : ""); if (to != 0) - fprintf(stderr, " to %d second%c from now.\n", - to, to > 1 ? 's' : 0); + fprintf(stderr, " to %d second%s from now.\n", + to, to > 1 ? "s" : ""); else fprintf(stderr, " off.\n"); } From 059220549cd080bae970a802856b2c44b2eeb3cc Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Wed, 22 Oct 2014 18:44:59 +0200 Subject: [PATCH 0041/1152] gitignore: adpat to scanner and protocol path changes Since commit 4c163b9b001bd93aaf97d7e962873a379eb90bfd, wayland-scanner is built in top builddir instead of src, and protocol files are generated in protocol subdir instead of src. Protocol files generated in the new path are already properly ignored in the toplevel gitignore file. Signed-off-by: Olivier Blin Reviewed-by: Pekka Paalanen --- .gitignore | 2 +- src/.gitignore | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index d9d26ed3..4e0f5d92 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,5 @@ resources-test sanity-test signal-test socket-test -wayland-scanner +/wayland-scanner protocol/*.[ch] diff --git a/src/.gitignore b/src/.gitignore index 1438b744..4421b46d 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,5 +1 @@ -wayland-scanner -wayland-client-protocol.h -wayland-protocol.c -wayland-server-protocol.h /wayland-version.h From 59f255d66e4dad89f633deec535482faa8bd8561 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Mon, 27 Oct 2014 09:19:46 +0100 Subject: [PATCH 0042/1152] client: read_events should return -1 after an error When a thread is sleeping, waiting until another thread read from the display, it always returns 0. Even when an error occured. In documentation stands: "return 0 on success or -1 on error. In case of error errno will be set accordingly" So this is a fix for this. Along with the read_events, fix a test so that it now complies with this behaviour (and we have this tested) Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- src/wayland-client.c | 5 +++++ tests/display-test.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 01629e01..7df22d09 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1190,6 +1190,11 @@ read_events(struct wl_display *display) while (display->read_serial == serial) pthread_cond_wait(&display->reader_cond, &display->mutex); + + if (display->last_error) { + errno = display->last_error; + return -1; + } } return 0; diff --git a/tests/display-test.c b/tests/display-test.c index aecf3411..d5f4d00c 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -369,9 +369,9 @@ thread_read_error(void *data) * thread should be woken up or it will block indefinitely. */ c->display_stopped = 1; - assert(wl_display_read_events(c->wl_display) == 0); + assert(wl_display_read_events(c->wl_display) == -1); - wl_display_dispatch_pending(c->wl_display); + assert(wl_display_dispatch_pending(c->wl_display) == -1); assert(wl_display_get_error(c->wl_display)); pthread_exit(NULL); From 11560a8d15435b06633659266b23128426d02ffc Mon Sep 17 00:00:00 2001 From: Imran Zaman Date: Mon, 24 Nov 2014 16:10:49 +0200 Subject: [PATCH 0043/1152] server: increase listen queue to 128 This will allow more than 1 simultaneous client connections to the server without the possibility of connection refused error. Signed-off-by: Imran Zaman http://utcc.utoronto.ca/~cks/space/blog/unix/ListenBacklogMeaning http://stackoverflow.com/questions/19221105/connect-with-unix-domain-socket-and-full-backlog Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index c40d3001..c845dd68 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1139,7 +1139,7 @@ _wl_display_add_socket(struct wl_display *display, struct wl_socket *s) return -1; } - if (listen(s->fd, 1) < 0) { + if (listen(s->fd, 128) < 0) { wl_log("listen() failed with error: %m\n"); return -1; } From d8f045ec1f8f48049b9c5e4e589e43b1cf3813d8 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:42:54 -0800 Subject: [PATCH 0044/1152] doc: make rebuilds doxygen output on code changes Reviewed-by: Bryce Harrington --- doc/publican/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index cf0f533f..b30a4719 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -82,7 +82,7 @@ en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/proto # move it out of the way first. # * use doxygen's combine.xslt to merge the xml files into one single file # * move wayland-_8h.xml back to its original location -en-US/%API.xml.tmp: +en-US/%API.xml.tmp: $(top_builddir)/doc/doxygen/xml/%/index.xml $(AM_V_GEN)mv $(top_builddir)/doc/doxygen/xml/$*/wayland-$*_8h.xml \ $(top_builddir)/doc/doxygen/xml/ $(AM_V_GEN)$(XSLTPROC) $(top_builddir)/doc/doxygen/xml/$*/combine.xslt \ From c532b571e3401aab8b61a0e267979d1ed558cd87 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:42:55 -0800 Subject: [PATCH 0045/1152] doc: Preserve spaces Slight variation on Pekka's patch. It seems harmless to put this anywhere. --- doc/publican/doxygen-to-publican.xsl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index b6ca5f3b..99193e1f 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -108,6 +108,10 @@ + + + + From ba8ea938d2121cf98581f0316f4ded48d412e215 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:42:56 -0800 Subject: [PATCH 0046/1152] doc: preserve links produced by Doxygen These links are pretty useful for navigation, though sometimes excessive (you can turn them off by putting % before the word in the comment). I had to turn off validation because it failed on missing and duplicate target id's, which this produces. --- doc/publican/Makefile.am | 1 + doc/publican/doxygen-to-publican.xsl | 23 ++++++++--------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index b30a4719..9fc4e0ba 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -47,6 +47,7 @@ if HAVE_XMLTO if HAVE_XSLTPROC noinst_DATA = Wayland $(publican_targets) XMLTO_PARAM = \ + --skip-validation \ --stringparam chunk.section.depth=0 \ --stringparam toc.section.depth=1 \ --stringparam html.stylesheet=css/default.css diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 99193e1f..7f7abe9b 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -61,7 +61,7 @@ - + @@ -81,10 +81,7 @@ - See also: - - - + See also: @@ -94,7 +91,7 @@ - Since: + Since: @@ -104,10 +101,6 @@ Note: - - - - @@ -135,9 +128,9 @@ - + - + - @@ -154,8 +147,8 @@ - - + + @@ -164,7 +157,7 @@ - + From f2974c1115dd2191e1352574283ca43729eaf7b8 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:42:57 -0800 Subject: [PATCH 0047/1152] doc: Don't print dash if doxygen brief description missing --- doc/publican/doxygen-to-publican.xsl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 7f7abe9b..461cf3eb 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -131,7 +131,9 @@ - - + + - + @@ -150,8 +152,8 @@ - - + + - From dd534a1fde4ffcb76be10810963832aea5f95a25 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:42:58 -0800 Subject: [PATCH 0048/1152] doc: removed some unnecessary nested listing from doxygen output This makes the lists of parameters slightly smaller and removes some bullets from see-also and since. --- doc/publican/doxygen-to-publican.xsl | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 461cf3eb..d8f3289d 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -45,9 +45,7 @@ - - - + @@ -69,32 +67,22 @@ Returns: - - - + - - - - See also: - - - + + See also: + - - - - Since: - - - + + Since: + From 40aa80a4082975d1598f4896a751c0562be9016b Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:42:59 -0800 Subject: [PATCH 0049/1152] doc: Added \code tags around sample code in doxygen comments Also removed \comment and used C++ comments. There does not appear to be any other way to put comments into code samples. Reviewed-by: Bryce Harrington --- src/wayland-client.c | 25 ++++++++++++++----------- src/wayland-server.h | 8 ++++---- src/wayland-util.h | 30 ++++++++++++++---------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 7df22d09..06f2765c 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1326,10 +1326,12 @@ wl_display_prepare_read_queue(struct wl_display *display, * it will assume the file descriptor is readable and read events from * the fd by calling wl_display_dispatch(). Simplified, we have: * - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * poll(fds, nfds, -1); - * wl_display_dispatch(display); + * \code + * wl_display_dispatch_pending(display); + * wl_display_flush(display); + * poll(fds, nfds, -1); + * wl_display_dispatch(display); + * \endcode * * There are two races here: first, before blocking in poll(), the fd * could become readable and another thread reads the events. Some of @@ -1344,13 +1346,14 @@ wl_display_prepare_read_queue(struct wl_display *display, * fds in the event loop. * * A correct sequence would be: - * - * while (wl_display_prepare_read(display) != 0) - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * poll(fds, nfds, -1); - * wl_display_read_events(display); - * wl_display_dispatch_pending(display); + * \code + * while (wl_display_prepare_read(display) != 0) + * wl_display_dispatch_pending(display); + * wl_display_flush(display); + * poll(fds, nfds, -1); + * wl_display_read_events(display); + * wl_display_dispatch_pending(display); + * \endcode * * Here we call wl_display_prepare_read(), which ensures that between * returning from that call and eventually calling diff --git a/src/wayland-server.h b/src/wayland-server.h index 38855c90..af2f03d5 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -144,18 +144,18 @@ wl_client_post_no_memory(struct wl_client *client); * listener should be done through provided accessor methods. A listener can * only listen to one signal at a time. * - * ~~~ + * \code * struct wl_listener your_listener; * * your_listener.notify = your_callback_method; * - * \comment{Direct access} + * // Direct access * wl_signal_add(&some_object->destroy_signal, &your_listener); * - * \comment{Accessor access} + * // Accessor access * wl_event_loop *loop = ...; * wl_event_loop_add_destroy_listener(loop, &your_listener); - * ~~~ + * \endcode * * If the listener is part of a larger struct, #wl_container_of can be used * to retrieve a pointer to it: diff --git a/src/wayland-util.h b/src/wayland-util.h index 05e50ddd..46f9a818 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -88,8 +88,7 @@ struct wl_interface { * "item_t", and the item member as "struct wl_list link". * * The following code will initialize a list: - * - * ~~~ + * \code * struct wl_list foo_list; * * struct item_t { @@ -99,20 +98,19 @@ struct wl_interface { * struct item_t item1, item2, item3; * * wl_list_init(&foo_list); - * wl_list_insert(&foo_list, &item1.link); \comment{Pushes item1 at the head} - * wl_list_insert(&foo_list, &item2.link); \comment{Pushes item2 at the head} - * wl_list_insert(&item2.link, &item3.link); \comment{Pushes item3 after item2} - * ~~~ + * wl_list_insert(&foo_list, &item1.link); // Pushes item1 at the head + * wl_list_insert(&foo_list, &item2.link); // Pushes item2 at the head + * wl_list_insert(&item2.link, &item3.link); // Pushes item3 after item2 + * \endcode * * The list now looks like [item2, item3, item1] * - * Will iterate the list in ascending order: - * + * Iterate the list in ascending order: * \code - * item_t *item; - * wl_list_for_each(item, foo_list, link) { - * Do_something_with_item(item); - * } + * item_t *item; + * wl_list_for_each(item, foo_list, link) { + * Do_something_with_item(item); + * } * \endcode */ struct wl_list { @@ -138,10 +136,10 @@ void wl_list_insert_list(struct wl_list *list, struct wl_list *other); * To demonstrate, the following example retrieves a pointer to * `example_container` given only its `destroy_listener` member: * - * ~~~ + * \code * struct example_container { * struct wl_listener destroy_listener; - * \comment{other members...} + * // other members... * }; * * void example_container_destroy(struct wl_listener *listener, void *data) @@ -149,9 +147,9 @@ void wl_list_insert_list(struct wl_list *list, struct wl_list *other); * struct example_container *ctr; * * ctr = wl_container_of(listener, ctr, destroy_listener); - * \comment{destroy ctr...} + * // destroy ctr... * } - * ~~~ + * \endcode * * \param ptr A valid pointer to the contained item. * From 5e79171cf16de84ee8e89b3fd3af4d39dcbd4171 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Thu, 13 Nov 2014 14:46:51 -0800 Subject: [PATCH 0050/1152] v4 doc: fixed reference to non-existent function (Fixed to remove accidental commit of another change) After some feedback from Marek Chalupa I decided to just remove this. There were suggestions about warning about multiple threads but it appears this would be true for many of these functions and thus it would be misleading to mention multiple threads only here (as it would imply that multiple threads work for other functions which is not true, I think). Acked-by: Marek Chalupa --- src/wayland-client.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 06f2765c..836246e8 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1510,9 +1510,6 @@ wl_display_dispatch_queue_pending(struct wl_display *display, * or not. For dispatching main queue events without blocking, see \ref * wl_display_dispatch_pending(). * - * \note Calling this will release the display file descriptor if this - * thread acquired it using wl_display_acquire_fd(). - * * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue() * * \memberof wl_display From f73f76775fa034e8a5f7b6347f38880df3d94e91 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:43:01 -0800 Subject: [PATCH 0051/1152] doc: fixed a typo Reviewed-by: Bryce Harrington --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 836246e8..41fca6d0 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1217,7 +1217,7 @@ cancel_read(struct wl_display *display) * This will read events from the file descriptor for the display. * This function does not dispatch events, it only reads and queues * events into their corresponding event queues. If no data is - * avilable on the file descriptor, wl_display_read_events() returns + * available on the file descriptor, wl_display_read_events() returns * immediately. To dispatch events that may have been queued, call * wl_display_dispatch_pending() or * wl_display_dispatch_queue_pending(). From dfdb0878264b72d49c263b87952f9fec85e278c2 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 11 Nov 2014 18:43:02 -0800 Subject: [PATCH 0052/1152] doc: Removed \ref when it refers to the subject the text is attached to This does not make a difference to doxygen output but may help other document generators not make redundant links. Reviewed-by: Bryce Harrington --- src/wayland-client.c | 2 +- src/wayland-client.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 41fca6d0..db441299 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1539,7 +1539,7 @@ wl_display_dispatch(struct wl_display *display) * to dispatch. * * To proper integrate the wayland display fd into a main loop, the - * client should always call \ref wl_display_dispatch_pending() and then + * client should always call wl_display_dispatch_pending() and then * \ref wl_display_flush() prior to going back to sleep. At that point, * the fd typically doesn't have data so attempting I/O could block, but * events queued up on the main queue should be dispatched. diff --git a/src/wayland-client.h b/src/wayland-client.h index 0801a818..dd42d7b3 100644 --- a/src/wayland-client.h +++ b/src/wayland-client.h @@ -41,7 +41,7 @@ extern "C" { * turn call the handler set with \ref wl_proxy_add_listener(). * * \note With the exception of function \ref wl_proxy_set_queue(), functions - * accessing a \ref wl_proxy are not normally used by client code. Clients + * accessing a wl_proxy are not normally used by client code. Clients * should normally use the higher level interface generated by the scanner to * interact with compositor objects. * @@ -53,15 +53,15 @@ struct wl_proxy; * \brief Represents a connection to the compositor and acts as a proxy to * the wl_display singleton object. * - * A \ref wl_display object represents a client connection to a Wayland + * A wl_display object represents a client connection to a Wayland * compositor. It is created with either \ref wl_display_connect() or * \ref wl_display_connect_to_fd(). A connection is terminated using * \ref wl_display_disconnect(). * - * A \ref wl_display is also used as the \ref wl_proxy for the \ref wl_display + * A wl_display is also used as the \ref wl_proxy for the wl_display * singleton object on the compositor side. * - * A \ref wl_display object handles all the data sent from and to the + * A wl_display object handles all the data sent from and to the * compositor. When a \ref wl_proxy marshals a request, it will write its wire * representation to the display's write buffer. The data is sent to the * compositor when the client calls \ref wl_display_flush(). @@ -71,7 +71,7 @@ struct wl_proxy; * added to a queue. On the dispatch step, the handler for the incoming * event set by the client on the corresponding \ref wl_proxy is called. * - * A \ref wl_display has at least one event queue, called the main + * A wl_display has at least one event queue, called the main * queue. Clients can create additional event queues with \ref * wl_display_create_queue() and assign \ref wl_proxy's to it. Events * occurring in a particular proxy are always queued in its assigned queue. From 266b7f06bee13b06f2a73cb7330382de69cbf1ce Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 25 Nov 2014 17:41:03 -0800 Subject: [PATCH 0053/1152] doc: Removed extra indentation from wl_list code sample This is a minor documentation fix. I did not see any asterisks in the output as reported by Pekka Paalanen. Using doxygen 1.7.6.1. Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 46f9a818..a4b22b54 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -107,10 +107,10 @@ struct wl_interface { * * Iterate the list in ascending order: * \code - * item_t *item; - * wl_list_for_each(item, foo_list, link) { - * Do_something_with_item(item); - * } + * item_t *item; + * wl_list_for_each(item, foo_list, link) { + * Do_something_with_item(item); + * } * \endcode */ struct wl_list { From e36d0233ee2d4e31a27c5e4b7b3a39c872267a69 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 17 Nov 2014 14:59:14 -0600 Subject: [PATCH 0054/1152] doc: fixed grammar and a typo Signed-off-by: Derek Foreman --- src/wayland-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index db441299..36380fe2 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -427,8 +427,8 @@ wl_proxy_add_listener(struct wl_proxy *proxy, * Gets the address to the proxy's listener; which is the listener set with * \ref wl_proxy_add_listener. * - * This function is useful in client with multiple listeners on the same - * interface to allow the identification of which code to eexecute. + * This function is useful in clients with multiple listeners on the same + * interface to allow the identification of which code to execute. * * \memberof wl_proxy */ From 93e352d05808820664f8bcb362785d1861b78ccb Mon Sep 17 00:00:00 2001 From: Seedo Eldho Paul Date: Thu, 27 Nov 2014 20:50:14 +0530 Subject: [PATCH 0055/1152] scanner.c: Use WL_PRINTF instead of __attribute__((format(printf))) Signed-off-by: Seedo Eldho Paul --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index fa8e0c0a..ca03c57c 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -199,7 +199,7 @@ static const char *indent(int n) } static void -desc_dump(char *desc, const char *fmt, ...) __attribute__((format(printf,2,3))); +desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3); static void desc_dump(char *desc, const char *fmt, ...) From bef2948348748d1144b2b620fb8fb4bcdd5c0e02 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 28 Nov 2014 09:41:50 +0100 Subject: [PATCH 0056/1152] tests: rename env vars for tests Rename WAYLAND_TESTS_NO_TIMEOUTS to WAYLAND_TEST_NO_TIMEOUTS. Further rename NO_ASSERT_LEAK_CHECK to WAYLAND_TEST_NO_LEAK_CHECK. Now the naming is consistent not only here, in Wayland, but even with naming of weston env varibles related to testing. This is version 2 of the patch. The first version just renamed NO_ASSERT_LEAK_CHECK to WAYLAND_TEST_NO_LEAK_CHECK. Signed-off-by: Marek Chalupa Acked-by: Pekka Paalanen Acked-by: Bryce Harrington --- tests/test-runner.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index d965a43e..67763b3e 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -42,11 +42,14 @@ static void (*sys_free)(void*); static void* (*sys_realloc)(void*, size_t); static void* (*sys_calloc)(size_t, size_t); +/* when set to 1, check if tests are not leaking memory and opened files. + * It is turned on by default. It can be turned off by + * WAYLAND_TEST_NO_LEAK_CHECK environment variable. */ int leak_check_enabled; /* when this var is set to 0, every call to test_set_timeout() is * suppressed - handy when debugging the test. Can be set by - * WAYLAND_TESTS_NO_TIMEOUTS evnironment var */ + * WAYLAND_TEST_NO_TIMEOUTS evnironment var */ static int timeouts_enabled = 1; extern const struct test __start_test_section, __stop_test_section; @@ -234,8 +237,8 @@ int main(int argc, char *argv[]) sys_malloc = dlsym(RTLD_NEXT, "malloc"); sys_free = dlsym(RTLD_NEXT, "free"); - leak_check_enabled = !getenv("NO_ASSERT_LEAK_CHECK"); - timeouts_enabled = !getenv("WAYLAND_TESTS_NO_TIMEOUTS"); + leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); + timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS"); if (argc == 2 && strcmp(argv[1], "--help") == 0) usage(argv[0], EXIT_SUCCESS); From 57050589b6e6242e1aa2b395444013c19bb19ee7 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 21 Nov 2014 11:34:07 +0100 Subject: [PATCH 0057/1152] test-runner: print separator line after each test-case Who can read the output when it is a single piece of text? Signed-off-by: Marek Chalupa --- tests/test-runner.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test-runner.c b/tests/test-runner.c index 67763b3e..b6ea0980 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -296,6 +296,9 @@ int main(int argc, char *argv[]) fprintf(stderr, ", pass.\n"); } else fprintf(stderr, ", fail.\n"); + + /* print separator line */ + fprintf(stderr, "----------------------------------------\n"); } total = &__stop_test_section - &__start_test_section; From 0e1cc7aba7b28ff40d91c3d0c0dba834f72d2486 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 28 Nov 2014 13:18:20 +0100 Subject: [PATCH 0058/1152] tests: use color when printing on terminal Colorize output of the tests when prinitng on terminal. Signed-off-by: Marek Chalupa Tested-by: Pekka Paalanen --- tests/test-runner.c | 52 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index b6ea0980..431511a3 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -52,6 +52,9 @@ int leak_check_enabled; * WAYLAND_TEST_NO_TIMEOUTS evnironment var */ static int timeouts_enabled = 1; +/* set to one if the output goes to the terminal */ +static int is_atty = 0; + extern const struct test __start_test_section, __stop_test_section; __attribute__ ((visibility("default"))) void * @@ -224,6 +227,25 @@ rmdir_xdg_runtime_dir(void) perror("Cleaning XDG_RUNTIME_DIR"); } +#define RED "\033[31m" +#define GREEN "\033[32m" + +static void +stderr_set_color(const char *color) +{ + /* use colors only when the output is connected to + * the terminal */ + if (is_atty) + fprintf(stderr, "%s", color); +} + +static void +stderr_reset_color(void) +{ + if (is_atty) + fprintf(stderr, "\033[0m"); +} + int main(int argc, char *argv[]) { const struct test *t; @@ -240,6 +262,9 @@ int main(int argc, char *argv[]) leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS"); + if (isatty(fileno(stderr))) + is_atty = 1; + if (argc == 2 && strcmp(argv[1], "--help") == 0) usage(argv[0], EXIT_SUCCESS); @@ -271,32 +296,45 @@ int main(int argc, char *argv[]) run_test(t); /* never returns */ if (waitid(P_ALL, 0, &info, WEXITED)) { + stderr_set_color(RED); fprintf(stderr, "waitid failed: %m\n"); + stderr_reset_color(); + abort(); } - fprintf(stderr, "test \"%s\":\t", t->name); switch (info.si_code) { case CLD_EXITED: - fprintf(stderr, "exit status %d", info.si_status); if (info.si_status == EXIT_SUCCESS) - success = 1; + success = !t->must_fail; + else + success = t->must_fail; + + stderr_set_color(success ? GREEN : RED); + fprintf(stderr, "test \"%s\":\texit status %d", + t->name, info.si_status); + break; case CLD_KILLED: case CLD_DUMPED: - fprintf(stderr, "signal %d", info.si_status); + if (t->must_fail) + success = 1; + + stderr_set_color(success ? GREEN : RED); + fprintf(stderr, "test \"%s\":\tsignal %d", + t->name, info.si_status); + break; } - if (t->must_fail) - success = !success; - if (success) { pass++; fprintf(stderr, ", pass.\n"); } else fprintf(stderr, ", fail.\n"); + stderr_reset_color(); + /* print separator line */ fprintf(stderr, "----------------------------------------\n"); } From c3653f7f61c9ced4f3e0243dc6f39f1efbe45c86 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 28 Nov 2014 15:36:52 +0100 Subject: [PATCH 0059/1152] tests: detect if debugger is attached Copy function from libinput/test/litest.c is_debugger_detached() and use it in our test-runner. If debugger is attached, turn off leak checks and timeouts automatically. Revision of libinput: 028513a0a723e97941c39c4aeb17433198723913 v2. rebased to master Signed-off-by: Marek Chalupa Acked-by: Pekka Paalanen --- tests/test-runner.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 431511a3..753617fa 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "test-runner.h" @@ -246,6 +247,38 @@ stderr_reset_color(void) fprintf(stderr, "\033[0m"); } +/* this function is taken from libinput/test/litest.c + * (rev 028513a0a723e97941c39) + */ +static int +is_debugger_attached(void) +{ + int status; + int rc; + int pid = fork(); + + if (pid == -1) + return 0; + + if (pid == 0) { + int ppid = getppid(); + if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0) { + waitpid(ppid, NULL, 0); + ptrace(PTRACE_CONT, NULL, NULL); + ptrace(PTRACE_DETACH, ppid, NULL, NULL); + rc = 0; + } else { + rc = 1; + } + _exit(rc); + } else { + waitpid(pid, &status, 0); + rc = WEXITSTATUS(status); + } + + return rc; +} + int main(int argc, char *argv[]) { const struct test *t; @@ -259,12 +292,17 @@ int main(int argc, char *argv[]) sys_malloc = dlsym(RTLD_NEXT, "malloc"); sys_free = dlsym(RTLD_NEXT, "free"); - leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); - timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS"); - if (isatty(fileno(stderr))) is_atty = 1; + if (is_debugger_attached()) { + leak_check_enabled = 0; + timeouts_enabled = 0; + } else { + leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); + timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS"); + } + if (argc == 2 && strcmp(argv[1], "--help") == 0) usage(argv[0], EXIT_SUCCESS); From fdb519be08b35c7d9659b0476aec78c170f7680d Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 21 Nov 2014 11:15:24 +0100 Subject: [PATCH 0060/1152] tests: split queue-test testcases All the test-cases are in one test atm. It doesn't matter for the outcome, but when it is split to more tests, the debugging and reading the output is simpler. Signed-off-by: Marek Chalupa Acked-by: Pekka Paalanen --- tests/queue-test.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/queue-test.c b/tests/queue-test.c index d1bf37f9..9eb913c0 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -207,7 +207,7 @@ dummy_bind(struct wl_client *client, { } -TEST(queue) +TEST(queue_proxy_destroy) { struct display *d; const struct wl_interface *dummy_interfaces[] = { @@ -230,9 +230,27 @@ TEST(queue) client_create(d, client_test_proxy_destroy); display_run(d); + display_destroy(d); +} + +TEST(queue_multiple_queues) +{ + struct display *d = display_create(); + + test_set_timeout(2); + client_create(d, client_test_multiple_queues); display_run(d); + display_destroy(d); +} + +TEST(queue_roundtrip) +{ + struct display *d = display_create(); + + test_set_timeout(2); + client_create(d, client_test_queue_roundtrip); display_run(d); From e118c111783f89635986fecdd7990ce7dcb1363b Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 21 Nov 2014 11:18:33 +0100 Subject: [PATCH 0061/1152] tests: fix memory leak We didn't free the struct client that we got from client_connect() Signed-off-by: Marek Chalupa Acked-by: Pekka Paalanen --- tests/display-test.c | 23 +++++++++++++---------- tests/test-compositor.c | 1 + 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index d5f4d00c..f9889a88 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -154,6 +154,14 @@ bind_seat(struct wl_client *client, void *data, ci->data = res; } +static void +client_disconnect_nocheck(struct client *c) +{ + wl_proxy_destroy((struct wl_proxy *) c->tc); + wl_display_disconnect(c->wl_display); + free(c); +} + static void post_error_main(void) { @@ -170,8 +178,7 @@ post_error_main(void) /* don't call client_disconnect(c), because then the test would be * aborted due to checks for error in this function */ wl_proxy_destroy((struct wl_proxy *) seat); - wl_proxy_destroy((struct wl_proxy *) c->tc); - wl_display_disconnect(c->wl_display); + client_disconnect_nocheck(c); } TEST(post_error_to_one_client) @@ -224,8 +231,7 @@ post_error_main3(void) /* don't call client_disconnect(c), because then the test would be * aborted due to checks for error in this function */ wl_proxy_destroy((struct wl_proxy *) seat); - wl_proxy_destroy((struct wl_proxy *) c->tc); - wl_display_disconnect(c->wl_display); + client_disconnect_nocheck(c); } /* all the testcases could be in one TEST, but splitting it @@ -294,8 +300,7 @@ post_nomem_main(void) assert(wl_display_get_error(c->wl_display) == ENOMEM); wl_proxy_destroy((struct wl_proxy *) seat); - wl_proxy_destroy((struct wl_proxy *) c->tc); - wl_display_disconnect(c->wl_display); + client_disconnect_nocheck(c); } TEST(post_nomem_tst) @@ -413,8 +418,7 @@ threading_post_err(void) test_set_timeout(3); pthread_join(thread, NULL); - wl_proxy_destroy((struct wl_proxy *) c->tc); - wl_display_disconnect(c->wl_display); + client_disconnect_nocheck(c); } TEST(threading_errors_tst) @@ -565,8 +569,7 @@ threading_read_after_error(void) test_set_timeout(3); pthread_join(thread, NULL); - wl_proxy_destroy((struct wl_proxy *) c->tc); - wl_display_disconnect(c->wl_display); + client_disconnect_nocheck(c); } TEST(threading_read_after_error_tst) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 3248e2d5..6f86a857 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -452,6 +452,7 @@ client_disconnect(struct client *c) wl_proxy_destroy((struct wl_proxy *) c->tc); wl_display_disconnect(c->wl_display); + free(c); } /* num is number of clients that requests to stop display. From 8cda738a682d736ae07afa483daa9724fbe4815b Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Thu, 27 Nov 2014 12:30:52 -0800 Subject: [PATCH 0062/1152] doc: Removed redundant xslt output elements. Removed elements that were duplicated but with attributes in a different order. Standard tools are required to ignore the order of attributes in an element. Signed-off-by: Jon A. Cruz Reviewed-by: Peter Hutterer --- doc/publican/protocol-interfaces-to-docbook.xsl | 1 - doc/publican/protocol-to-docbook.xsl | 1 - 2 files changed, 2 deletions(-) diff --git a/doc/publican/protocol-interfaces-to-docbook.xsl b/doc/publican/protocol-interfaces-to-docbook.xsl index ad6bdda0..9cf06959 100644 --- a/doc/publican/protocol-interfaces-to-docbook.xsl +++ b/doc/publican/protocol-interfaces-to-docbook.xsl @@ -1,6 +1,5 @@ - diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 939ba40e..443228d8 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -1,6 +1,5 @@ - From 962de0d0cc53f6ec737d18e6f8f9483d05e41dbb Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Tue, 2 Dec 2014 17:54:07 -0800 Subject: [PATCH 0063/1152] doc: Invoke doxygen via the defined make variable. Invoke doxygen via the autoconf-defined make variable instead of directly. This brings it in line with standard makefile practices. Signed-off-by: Jon A. Cruz Reviewed-by: Peter Hutterer --- doc/doxygen/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 83622af6..f8d636e3 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -28,14 +28,14 @@ xml/client/index.xml: $(scanned_src_files_client) wayland.doxygen echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/client"; \ echo "INPUT= $(scanned_src_files_client)"; \ - ) | doxygen - + ) | $(DOXYGEN) - xml/server/index.xml: $(scanned_src_files_server) wayland.doxygen $(AM_V_GEN)$(MKDIR_P) xml/server && \ (cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/server"; \ echo "INPUT= $(scanned_src_files_server)"; \ - ) | doxygen - + ) | $(DOXYGEN) - man/man3/wl_display.3: $(scanned_src_files_client) $(scanned_src_files_server) $(AM_V_GEN)(cat wayland.doxygen; \ @@ -43,7 +43,7 @@ man/man3/wl_display.3: $(scanned_src_files_client) $(scanned_src_files_server) echo "MAN_OUTPUT=man"; \ echo "JAVADOC_AUTOBRIEF=NO"; \ echo "INPUT= $^"; \ - ) | doxygen - + ) | $(DOXYGEN) - # there is no man-local all-local: man/man3/wl_display.3 From 0093164f85c7fdb5de4c45b6e3261d9c3c3ddcf4 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 2 Dec 2014 18:29:35 -0800 Subject: [PATCH 0064/1152] doc: removed redundant dependency The .tmp file dependency depends on the index.xml file so it does not need to be repeated. Reviewed-by: Peter Hutterer --- doc/publican/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 9fc4e0ba..0b2cd096 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -93,12 +93,12 @@ en-US/%API.xml.tmp: $(top_builddir)/doc/doxygen/xml/%/index.xml # WaylandClientAPI.xml: # merge doxygen xml files into one single file, then transform the combined XML file into docbook format -en-US/WaylandClientAPI.xml: en-US/clientAPI.xml.tmp $(top_builddir)/doc/doxygen/xml/client/index.xml $(srcdir)/doxygen-to-publican.xsl +en-US/WaylandClientAPI.xml: en-US/clientAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl $(AM_V_GEN)$(XSLTPROC) --stringparam which Client $(srcdir)/doxygen-to-publican.xsl \ $(builddir)/en-US/clientAPI.xml.tmp > en-US/WaylandClientAPI.xml # WaylandServerAPI.xml: see WaylandClientAPI.xml -en-US/WaylandServerAPI.xml: en-US/serverAPI.xml.tmp $(top_builddir)/doc/doxygen/xml/client/index.xml $(srcdir)/doxygen-to-publican.xsl +en-US/WaylandServerAPI.xml: en-US/serverAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl $(AM_V_GEN)$(XSLTPROC) --stringparam which Server $(srcdir)/doxygen-to-publican.xsl \ $(builddir)/en-US/serverAPI.xml.tmp > en-US/WaylandServerAPI.xml From 9ca542db4efcc912a28ca88f27875cdf65429a66 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 2 Dec 2014 18:29:36 -0800 Subject: [PATCH 0065/1152] doc: Remove duplicated descriptions of wayland objects This text is a duplicate of the text in the protocol documentation, but the converter mangled it by removing the paragraph breaks and some other errors. Instead replace it with a list of links to the protocol docs. Reviewed-by: Peter Hutterer --- doc/publican/protocol-interfaces-to-docbook.xsl | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/doc/publican/protocol-interfaces-to-docbook.xsl b/doc/publican/protocol-interfaces-to-docbook.xsl index 9cf06959..fb1a8160 100644 --- a/doc/publican/protocol-interfaces-to-docbook.xsl +++ b/doc/publican/protocol-interfaces-to-docbook.xsl @@ -34,21 +34,15 @@ - protocol-summary-- - - + + - - - - - - - - - + + + From 480b437cd87b6c268b083c970dfbfbd8ff1a0dae Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Wed, 3 Dec 2014 18:26:26 -0800 Subject: [PATCH 0066/1152] doc: Add config check for doxygen 1.6.0+. Add a config time check for a new enough (1.6.0+) version of doxygen. v2. require 1.6.0+ instead of 1.8.0+ Signed-off-by: Jon A. Cruz Reviewed-by: Pekka Paalanen --- configure.ac | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index 6f8220bd..12dd94c7 100644 --- a/configure.ac +++ b/configure.ac @@ -109,6 +109,14 @@ if test "x$enable_documentation" = "xyes"; then AC_MSG_ERROR([Documentation build requested but doxygen not found. Install doxygen or disable the documentation using --disable-documentation]) fi + AC_MSG_CHECKING([for compatible doxygen version]) + doxygen_version=`$DOXYGEN --version` + AS_VERSION_COMPARE([$doxygen_version], [1.6.0], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([Doxygen $doxygen_version too old. Doxygen 1.6+ required for documentation build. Install required doxygen version or disable the documentation using --disable-documentation])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([yes])]) + AC_PATH_PROG(XMLTO, xmlto) if test "x$XMLTO" = "x"; then From 77939736fb613896fb9f5d262cd877acfb2728d2 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Wed, 3 Dec 2014 15:53:16 +0100 Subject: [PATCH 0067/1152] client: update obsolete comments 1) there is nothing like main thread since 3c7e8bfbb4745315b7bcbf69fa746c3d6718c305 anymore, so remove it from documentation and update the doc accordingly. 2) use calling 'default queue' instead of 'main queue'. In the code we use display->default_queue, so it'll be easier the understand. 3) update some obsolete or unprecise pieces of documentation v2. Not only remove out-of-date comment, but fix/remove more things across the wayland-client.[ch] v3. fixes (rephrasing unclear paragraphs etc.) according to Pakka Paalanen notes (thanks) Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen Reviewed-by: Daniel Stone --- src/wayland-client.c | 82 +++++++++++++++++++++++++++----------------- src/wayland-client.h | 26 ++++++-------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 36380fe2..eae438a4 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1333,18 +1333,19 @@ wl_display_prepare_read_queue(struct wl_display *display, * wl_display_dispatch(display); * \endcode * - * There are two races here: first, before blocking in poll(), the fd - * could become readable and another thread reads the events. Some of - * these events may be for the main queue and the other thread will - * queue them there and then the main thread will go to sleep in - * poll(). This will stall the application, which could be waiting - * for a event to kick of the next animation frame, for example. - * - * The other race is immediately after poll(), where another thread - * could preempt and read events before the main thread calls - * wl_display_dispatch(). This call now blocks and starves the other + * The race is immediately after poll(), where one thread + * could preempt and read events before the other thread calls + * wl_display_dispatch(). This call now blocks and starves the other * fds in the event loop. * + * Another race would be when using more event queues. + * When one thread calls wl_display_dispatch(_queue)(), then it + * reads all events from display's fd and queues them in appropriate + * queues. Then it dispatches only its own queue and the other events + * are sitting in their queues, waiting for dispatching. If that happens + * before the other thread managed to call poll(), it will + * block with events queued. + * * A correct sequence would be: * \code * while (wl_display_prepare_read(display) != 0) @@ -1358,9 +1359,12 @@ wl_display_prepare_read_queue(struct wl_display *display, * Here we call wl_display_prepare_read(), which ensures that between * returning from that call and eventually calling * wl_display_read_events(), no other thread will read from the fd and - * queue events in our queue. If the call to - * wl_display_prepare_read() fails, we dispatch the pending events and - * try again until we're successful. + * queue events in our queue. If the call to wl_display_prepare_read() fails, + * we dispatch the pending events and try again until we're successful. + * + * If the relevant queue is not the default queue, then + * wl_display_prepare_read_queue() and wl_display_dispatch_queue_pending() + * need to be used instead. * * \memberof wl_display */ @@ -1399,10 +1403,25 @@ wl_display_cancel_read(struct wl_display *display) * Dispatch all incoming events for objects assigned to the given * event queue. On failure -1 is returned and errno set appropriately. * - * This function blocks if there are no events to dispatch. If calling from - * the main thread, it will block reading data from the display fd. For other - * threads this will block until the main thread queues events on the queue - * passed as argument. + * The behaviour of this function is exactly the same as the behaviour of + * wl_display_dispatch(), but it dispatches events on given queue, + * not on the default queue. + * + * This function blocks if there are no events to dispatch (if there are, + * it only dispatches these events and returns immediately). + * When this function returns after blocking, it means that it read events + * from display's fd and queued them to appropriate queues. + * If among the incoming events were some events assigned to the given queue, + * they are dispatched by this moment. + * + * \note Since Wayland 1.5 the display has an extra queue + * for its own events (i. e. delete_id). This queue is dispatched always, + * no matter what queue we passed as an argument to this function. + * That means that this function can return non-0 value even when it + * haven't dispatched any event for the given queue. + * + * \sa wl_display_dispatch(), wl_display_dispatch_pending(), + * wl_display_dispatch_queue_pending() * * \memberof wl_display */ @@ -1499,15 +1518,15 @@ wl_display_dispatch_queue_pending(struct wl_display *display, * \param display The display context object * \return The number of dispatched events on success or -1 on failure * - * Dispatch the display's main event queue. + * Dispatch the display's default event queue. * - * If the main event queue is empty, this function blocks until there are + * If the default event queue is empty, this function blocks until there are * events to be read from the display fd. Events are read and queued on - * the appropriate event queues. Finally, events on the main event queue + * the appropriate event queues. Finally, events on the default event queue * are dispatched. * - * \note It is not possible to check if there are events on the main queue - * or not. For dispatching main queue events without blocking, see \ref + * \note It is not possible to check if there are events on the queue + * or not. For dispatching default queue events without blocking, see \ref * wl_display_dispatch_pending(). * * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue() @@ -1520,7 +1539,7 @@ wl_display_dispatch(struct wl_display *display) return wl_display_dispatch_queue(display, &display->default_queue); } -/** Dispatch main queue events without reading from the display fd +/** Dispatch default queue events without reading from the display fd * * \param display The display context object * \return The number of dispatched events or -1 on failure @@ -1532,8 +1551,8 @@ wl_display_dispatch(struct wl_display *display) * This is necessary when a client's main loop wakes up on some fd other * than the display fd (network socket, timer fd, etc) and calls \ref * wl_display_dispatch_queue() from that callback. This may queue up - * events in the main queue while reading all data from the display fd. - * When the main thread returns to the main loop to block, the display fd + * events in other queues while reading all data from the display fd. + * When the main loop returns from the handler, the display fd * no longer has data, causing a call to \em poll(2) (or similar * functions) to block indefinitely, even though there are events ready * to dispatch. @@ -1542,16 +1561,14 @@ wl_display_dispatch(struct wl_display *display) * client should always call wl_display_dispatch_pending() and then * \ref wl_display_flush() prior to going back to sleep. At that point, * the fd typically doesn't have data so attempting I/O could block, but - * events queued up on the main queue should be dispatched. + * events queued up on the default queue should be dispatched. * * A real-world example is a main loop that wakes up on a timerfd (or a * sound card fd becoming writable, for example in a video player), which * then triggers GL rendering and eventually eglSwapBuffers(). * eglSwapBuffers() may call wl_display_dispatch_queue() if it didn't * receive the frame event for the previous frame, and as such queue - * events in the main queue. - * - * \note Calling this makes the current thread the main one. + * events in the default queue. * * \sa wl_display_dispatch(), wl_display_dispatch_queue(), * wl_display_flush() @@ -1732,10 +1749,13 @@ wl_proxy_get_class(struct wl_proxy *proxy) /** Assign a proxy to an event queue * * \param proxy The proxy object - * \param queue The event queue that will handle this proxy + * \param queue The event queue that will handle this proxy or NULL * * Assign proxy to event queue. Events coming from \c proxy will be - * queued in \c queue instead of the display's main queue. + * queued in \c queue from now. If queue is NULL, then the display's + * default queue is set to the proxy. + * + * \note By default, the queue set in proxy is the one inherited from parent. * * \sa wl_display_dispatch_queue() * diff --git a/src/wayland-client.h b/src/wayland-client.h index dd42d7b3..71cd822f 100644 --- a/src/wayland-client.h +++ b/src/wayland-client.h @@ -71,7 +71,7 @@ struct wl_proxy; * added to a queue. On the dispatch step, the handler for the incoming * event set by the client on the corresponding \ref wl_proxy is called. * - * A wl_display has at least one event queue, called the main + * A wl_display has at least one event queue, called the default * queue. Clients can create additional event queues with \ref * wl_display_create_queue() and assign \ref wl_proxy's to it. Events * occurring in a particular proxy are always queued in its assigned queue. @@ -80,31 +80,27 @@ struct wl_proxy; * called by assigning that proxy to an event queue and making sure that * this queue is only dispatched when the assumption holds. * - * The main queue is dispatched by calling \ref wl_display_dispatch(). - * This will dispatch any events queued on the main queue and attempt - * to read from the display fd if its empty. Events read are then queued - * on the appropriate queues according to the proxy assignment. Calling - * that function makes the calling thread the main thread. + * The default queue is dispatched by calling \ref wl_display_dispatch(). + * This will dispatch any events queued on the default queue and attempt + * to read from the display fd if it's empty. Events read are then queued + * on the appropriate queues according to the proxy assignment. * * A user created queue is dispatched with \ref wl_display_dispatch_queue(). - * If there are no events to dispatch this function will block. If this - * is called by the main thread, this will attempt to read data from the - * display fd and queue any events on the appropriate queues. If calling - * from any other thread, the function will block until the main thread - * queues an event on the queue being dispatched. + * This function behaves exactly the same as wl_display_dispatch() + * but it dispatches given queue instead of the default queue. * * A real world example of event queue usage is Mesa's implementation of * eglSwapBuffers() for the Wayland platform. This function might need - * to block until a frame callback is received, but dispatching the main + * to block until a frame callback is received, but dispatching the default * queue could cause an event handler on the client to start drawing * again. This problem is solved using another event queue, so that only * the events handled by the EGL code are dispatched during the block. * - * This creates a problem where the main thread dispatches a non-main + * This creates a problem where a thread dispatches a non-default * queue, reading all the data from the display fd. If the application * would call \em poll(2) after that it would block, even though there - * might be events queued on the main queue. Those events should be - * dispatched with \ref wl_display_dispatch_pending() before + * might be events queued on the default queue. Those events should be + * dispatched with \ref wl_display_dispatch_(queue_)pending() before * flushing and blocking. */ struct wl_display; From 434fd45e4b62a5e410020bbc124d8e3460729aa2 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 5 Dec 2014 14:00:05 +0100 Subject: [PATCH 0068/1152] client: update documentation about threading Remove out-dated documentation and add few more words about this topic. v2. replace a paragraph by better explanation from Pekka Paalanen fix other notes from reviewing v3. fix typo v4. fix flags for poll in an example add wl_display_cancel_read() to another example (so that user sees that it should be used) move proper use of wl_display_prepare_read before the explanation why it is wrong to use wl_display_displach Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen Reviewed-by: Daniel Stone --- src/wayland-client.c | 152 +++++++++++++++++++++++++++++++++---------- 1 file changed, 116 insertions(+), 36 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index eae438a4..9e8bdfec 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -909,6 +909,12 @@ static const struct wl_callback_listener sync_listener = { * Blocks until the server process all currently issued requests and * sends out pending events on the event queue. * + * \note This function uses wl_display_dispatch_queue() internally. If you + * are using wl_display_read_events() from more threads, don't use this function + * (or make sure that calling wl_display_roundtrip_queue() doesn't interfere + * with calling wl_display_prepare_read() and wl_display_read_events()) + * + * \sa wl_display_roundtrip() * \memberof wl_display */ WL_EXPORT int @@ -940,6 +946,11 @@ wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *qu * Blocks until the server process all currently issued requests and * sends out pending events on the default event queue. * + * \note This function uses wl_display_dispatch_queue() internally. If you + * are using wl_display_read_events() from more threads, don't use this function + * (or make sure that calling wl_display_roundtrip() doesn't interfere + * with calling wl_display_prepare_read() and wl_display_read_events()) + * * \memberof wl_display */ WL_EXPORT int @@ -1216,14 +1227,59 @@ cancel_read(struct wl_display *display) * * This will read events from the file descriptor for the display. * This function does not dispatch events, it only reads and queues - * events into their corresponding event queues. If no data is + * events into their corresponding event queues. If no data is * available on the file descriptor, wl_display_read_events() returns - * immediately. To dispatch events that may have been queued, call - * wl_display_dispatch_pending() or - * wl_display_dispatch_queue_pending(). + * immediately. To dispatch events that may have been queued, call + * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending(). * * Before calling this function, wl_display_prepare_read() must be - * called first. + * called first. When running in more threads (which is the usual + * case, since we'd use wl_display_dispatch() otherwise), every thread + * must call wl_display_prepare_read() before calling this function. + * + * After calling wl_display_prepare_read() there can be some extra code + * before calling wl_display_read_events(), for example poll() or alike. + * Example of code in a thread: + * + * \code + * + * while (wl_display_prepare_read(display) < 0) + * wl_display_dispatch_pending(display); + * wl_display_flush(display); + * + * ... some code ... + * + * fds[0].fd = wl_display_get_fd(display); + * fds[0].events = POLLIN; + * poll(fds, 1, -1); + * + * if (!everything_ok()) { + * wl_display_cancel_read(display); + * handle_error(); + * } + * + * if (wl_display_read_events(display) < 0) + * handle_error(); + * + * ... + * \endcode + * + * After wl_display_prepare_read() succeeds, other threads that enter + * wl_display_read_events() will sleep until the very last thread enters + * it too or cancels. Therefore when the display fd becomes (or already + * is) readable, wl_display_read_events() should be called as soon as + * possible to unblock all threads. If wl_display_read_events() will not + * be called, then wl_display_cancel_read() must be called instead to let + * the other threads continue. + * + * This function must not be called simultaneously with wl_display_dispatch(). + * It may lead to deadlock. If programmer wants, for some reason, use + * wl_display_dispatch() in one thread and wl_display_prepare_read() with + * wl_display_read_events() in another, extra care must be taken to serialize + * these calls, i. e. use mutexes or similar (on whole prepare + read sequence) + * + * \sa wl_display_prepare_read(), wl_display_cancel_read(), + * wl_display_dispatch_pending(), wl_display_dispatch() * * \memberof wl_display */ @@ -1301,17 +1357,17 @@ wl_display_prepare_read_queue(struct wl_display *display, return ret; } -/** Prepare to read events after polling file descriptor +/** Prepare to read events from the display's file descriptor * * \param display The display context object * \return 0 on success or -1 if event queue was not empty * * This function must be called before reading from the file - * descriptor using wl_display_read_events(). Calling - * wl_display_prepare_read() announces the calling threads intention + * descriptor using wl_display_read_events(). Calling + * wl_display_prepare_read() announces the calling thread's intention * to read and ensures that until the thread is ready to read and * calls wl_display_read_events(), no other thread will read from the - * file descriptor. This only succeeds if the event queue is empty + * file descriptor. This only succeeds if the event queue is empty * though, and if there are undispatched events in the queue, -1 is * returned and errno set to EAGAIN. * @@ -1320,11 +1376,30 @@ wl_display_prepare_read_queue(struct wl_display *display, * read intention by calling wl_display_cancel_read(). * * Use this function before polling on the display fd or to integrate - * the fd into a toolkit event loop in a race-free way. Typically, a - * toolkit will call wl_display_dispatch_pending() before sleeping, to - * make sure it doesn't block with unhandled events. Upon waking up, - * it will assume the file descriptor is readable and read events from - * the fd by calling wl_display_dispatch(). Simplified, we have: + * the fd into a toolkit event loop in a race-free way. + * A correct usage would be (we left out most of error checking): + * + * \code + * while (wl_display_prepare_read(display) != 0) + * wl_display_dispatch_pending(display); + * wl_display_flush(display); + * + * ret = poll(fds, nfds, -1); + * if (has_error(ret)) + * wl_display_cancel_read(display); + * else + * wl_display_read_events(display); + * + * wl_display_dispatch_pending(display); + * \endcode + * + * Here we call wl_display_prepare_read(), which ensures that between + * returning from that call and eventually calling + * wl_display_read_events(), no other thread will read from the fd and + * queue events in our queue. If the call to wl_display_prepare_read() fails, + * we dispatch the pending events and try again until we're successful. + * + * When using wl_display_dispatch() we'd have something like: * * \code * wl_display_dispatch_pending(display); @@ -1333,8 +1408,8 @@ wl_display_prepare_read_queue(struct wl_display *display, * wl_display_dispatch(display); * \endcode * - * The race is immediately after poll(), where one thread - * could preempt and read events before the other thread calls + * This sequence in not thread-safe. The race is immediately after poll(), + * where one thread could preempt and read events before the other thread calls * wl_display_dispatch(). This call now blocks and starves the other * fds in the event loop. * @@ -1346,26 +1421,20 @@ wl_display_prepare_read_queue(struct wl_display *display, * before the other thread managed to call poll(), it will * block with events queued. * - * A correct sequence would be: - * \code - * while (wl_display_prepare_read(display) != 0) - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * poll(fds, nfds, -1); - * wl_display_read_events(display); - * wl_display_dispatch_pending(display); - * \endcode - * - * Here we call wl_display_prepare_read(), which ensures that between - * returning from that call and eventually calling - * wl_display_read_events(), no other thread will read from the fd and - * queue events in our queue. If the call to wl_display_prepare_read() fails, - * we dispatch the pending events and try again until we're successful. + * wl_display_prepare_read() function doesn't acquire exclusive access + * to the display's fd. It only registers that the thread calling this function + * has intention to read from fd. + * When all registered readers call wl_display_read_events(), + * only one (at random) eventually reads and queues the events and the + * others are sleeping meanwhile. This way we avoid races and still + * can read from more threads. * * If the relevant queue is not the default queue, then * wl_display_prepare_read_queue() and wl_display_dispatch_queue_pending() * need to be used instead. * + * \sa wl_display_cancel_read(), wl_display_read_events() + * * \memberof wl_display */ WL_EXPORT int @@ -1374,13 +1443,15 @@ wl_display_prepare_read(struct wl_display *display) return wl_display_prepare_read_queue(display, &display->default_queue); } -/** Release exclusive access to display file descriptor +/** Cancel read intention on display's fd * * \param display The display context object * - * This releases the exclusive access. Useful for canceling the lock - * when a timed out poll returns fd not readable and we're not going - * to read from the fd anytime soon. + * After a thread successfully called wl_display_prepare_read() it must + * either call wl_display_read_events() or wl_display_cancel_read(). + * If the threads do not follow this rule it will lead to deadlock. + * + * \sa wl_display_prepare_read(), wl_display_read_events() * * \memberof wl_display */ @@ -1420,6 +1491,9 @@ wl_display_cancel_read(struct wl_display *display) * That means that this function can return non-0 value even when it * haven't dispatched any event for the given queue. * + * This function has the same constrains for using in multi-threaded apps + * as \ref wl_display_dispatch(). + * * \sa wl_display_dispatch(), wl_display_dispatch_pending(), * wl_display_dispatch_queue_pending() * @@ -1525,11 +1599,17 @@ wl_display_dispatch_queue_pending(struct wl_display *display, * the appropriate event queues. Finally, events on the default event queue * are dispatched. * + * In multi-threaded environment, programmer may want to use + * wl_display_read_events(). However, use of wl_display_read_events() + * must not be mixed with wl_display_dispatch(). See wl_display_read_events() + * and wl_display_prepare_read() for more details. + * * \note It is not possible to check if there are events on the queue * or not. For dispatching default queue events without blocking, see \ref * wl_display_dispatch_pending(). * - * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue() + * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue(), + * wl_display_read_events() * * \memberof wl_display */ From dec30252b0a85930237bbe3369ea0bf378a603ec Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Tue, 9 Dec 2014 01:34:22 -0800 Subject: [PATCH 0069/1152] doc: General makefile cleanup. This is a general cleanup of the makefile in order to bring it more inline with standard make practices. Cleanups included more use of automatic variables, switching AM_V_GEN to AM_V_at to have one 'GEN' visible per file, splitting copy operations to proper rules, and using order only dependencies to properly create directories on-demand. Changes also correct missing use of $(builddir) that has gone unnoticed as it defaults to the current directory ('.'). Signed-off-by: Jon A. Cruz Acked-by: Peter Hutterer Acked-by: Pekka Paalanen --- doc/publican/Makefile.am | 77 ++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 0b2cd096..8ed3815c 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -13,6 +13,7 @@ # * WaylandServerAPI.xml is generated from the doxygen output and saved in # $(builddir)/en-US # * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US + publican_sources = \ $(srcdir)/sources/Wayland.ent \ $(srcdir)/sources/Wayland.xml \ @@ -37,6 +38,7 @@ css_sources = \ $(srcdir)/sources/css/default.css \ $(srcdir)/sources/css/epub.css \ $(srcdir)/sources/css/print.css + img_sources = \ $(srcdir)/sources/images/icon.svg \ $(srcdir)/sources/images/wayland-architecture.png \ @@ -45,71 +47,84 @@ img_sources = \ if HAVE_XMLTO if HAVE_XSLTPROC -noinst_DATA = Wayland $(publican_targets) +noinst_DATA = $(builddir)/Wayland $(publican_targets) XMLTO_PARAM = \ --skip-validation \ --stringparam chunk.section.depth=0 \ --stringparam toc.section.depth=1 \ --stringparam html.stylesheet=css/default.css +doxydir := $(top_builddir)/doc/doxygen + html_destdir = $(builddir)/Wayland/en-US/html -Wayland: $(publican_targets) - $(AM_V_GEN)$(MKDIR_P) -p $(html_destdir)/css - $(AM_V_GEN)cp -f $(css_sources) $(html_destdir)/css/ - $(AM_V_GEN)$(MKDIR_P) -p $(html_destdir)/images - $(AM_V_GEN)cp -f $(img_sources) $(html_destdir)/images/ - $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html en-US/Wayland.xml -o $(html_destdir) - @touch Wayland +# Listing various directories that might need to be created. +alldirs := $(builddir)/en-US $(builddir)/en-US/images $(html_destdir) $(html_destdir)/css $(html_destdir)/images + + +html_css_targets = $(addprefix $(html_destdir)/css/,$(notdir $(css_sources))) +html_img_targets = $(addprefix $(html_destdir)/images/,$(notdir $(img_sources))) + +$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) | $(builddir)/en-US + $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html $(builddir)/en-US/Wayland.xml -o $(html_destdir) + @touch $@ + +$(html_destdir)/css/%: $(srcdir)/sources/css/% | $(html_destdir)/css + $(AM_V_GEN)cp -f $< $@ + +$(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images + $(AM_V_GEN)cp -f $< $@ pubdir = $(docdir)/Wayland/en-US -publican_targets = $(publican_sources:$(srcdir)/sources%=$(builddir)/en-US%) \ - en-US/ProtocolSpec.xml en-US/ProtocolInterfaces.xml \ - en-US/WaylandClientAPI.xml en-US/WaylandServerAPI.xml +publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \ + $(builddir)/en-US/ProtocolSpec.xml $(builddir)/en-US/ProtocolInterfaces.xml \ + $(builddir)/en-US/WaylandClientAPI.xml $(builddir)/en-US/WaylandServerAPI.xml # The Protocol.xml is purely generated and required before running publican -en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-to-docbook.xsl - $(AM_V_GEN)$(MKDIR_P) en-US/images +$(builddir)/en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-to-docbook.xsl | $(builddir)/en-US $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-to-docbook.xsl \ - $(top_srcdir)/protocol/wayland.xml > en-US/ProtocolSpec.xml + $(top_srcdir)/protocol/wayland.xml > $@ -en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl - $(AM_V_GEN)$(MKDIR_P) en-US/images +$(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-interfaces-to-docbook.xsl \ - $(top_srcdir)/protocol/wayland.xml > en-US/ProtocolInterfaces.xml + $(top_srcdir)/protocol/wayland.xml > $@ # * we don't want wayland-{server|client}_8h.xml to avoid duplicating output methods, # move it out of the way first. # * use doxygen's combine.xslt to merge the xml files into one single file # * move wayland-_8h.xml back to its original location -en-US/%API.xml.tmp: $(top_builddir)/doc/doxygen/xml/%/index.xml - $(AM_V_GEN)mv $(top_builddir)/doc/doxygen/xml/$*/wayland-$*_8h.xml \ - $(top_builddir)/doc/doxygen/xml/ - $(AM_V_GEN)$(XSLTPROC) $(top_builddir)/doc/doxygen/xml/$*/combine.xslt \ - $(top_builddir)/doc/doxygen/xml/$*/index.xml > $@ - $(AM_V_GEN)mv $(top_builddir)/doc/doxygen/xml/wayland-$*_8h.xml \ - $(top_builddir)/doc/doxygen/xml/$* +$(builddir)/en-US/%API.xml.tmp: $(doxydir)/xml/%/index.xml | $(builddir)/en-US + $(AM_V_at)mv $(doxydir)/xml/$*/wayland-$*_8h.xml \ + $(doxydir)/xml/ + $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \ + $(doxydir)/xml/$*/index.xml > $@ + $(AM_V_at)mv $(doxydir)/xml/wayland-$*_8h.xml \ + $(doxydir)/xml/$* # WaylandClientAPI.xml: # merge doxygen xml files into one single file, then transform the combined XML file into docbook format -en-US/WaylandClientAPI.xml: en-US/clientAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl +$(builddir)/en-US/WaylandClientAPI.xml: $(builddir)/en-US/clientAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US $(AM_V_GEN)$(XSLTPROC) --stringparam which Client $(srcdir)/doxygen-to-publican.xsl \ - $(builddir)/en-US/clientAPI.xml.tmp > en-US/WaylandClientAPI.xml + $(builddir)/en-US/clientAPI.xml.tmp > $@ # WaylandServerAPI.xml: see WaylandClientAPI.xml -en-US/WaylandServerAPI.xml: en-US/serverAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl +$(builddir)/en-US/WaylandServerAPI.xml: $(builddir)/en-US/serverAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US $(AM_V_GEN)$(XSLTPROC) --stringparam which Server $(srcdir)/doxygen-to-publican.xsl \ - $(builddir)/en-US/serverAPI.xml.tmp > en-US/WaylandServerAPI.xml + $(builddir)/en-US/serverAPI.xml.tmp > $@ # Copy the sources source files into en-US destination # This is required for out-of-source-tree build as publican does not allow us # to specify the location of the source code. -$(builddir)/en-US/%: $(srcdir)/sources/% en-US/ProtocolSpec.xml en-US/ProtocolInterfaces.xml en-US/WaylandClientAPI.xml $(publican_sources) +$(builddir)/en-US/%: $(srcdir)/sources/% $(builddir)/en-US/ProtocolSpec.xml $(builddir)/en-US/ProtocolInterfaces.xml $(builddir)/en-US/WaylandClientAPI.xml $(publican_sources) | $(builddir)/en-US/images $(AM_V_GEN)cp -f $< $@ - $(AM_V_GEN)chmod a+w $@ + $(AM_V_at)chmod a+w $@ -CLEANFILES = en-US/ProtocolSpec.xml en-US/ProtocolInterfaces.xml en-US/WaylandClientAPI.xml $(publican_targets) +# general rule to create one of the listed directories. +$(alldirs): + $(AM_V_GEN)$(MKDIR_P) $@ + +CLEANFILES = $(builddir)/en-US/ProtocolSpec.xml $(builddir)/en-US/ProtocolInterfaces.xml $(builddir)/en-US/WaylandClientAPI.xml $(publican_targets) clean-local: $(AM_V_at)rm -fr $(builddir)/en-US From 163ce87cd732702328f76d20f24099041bb119ec Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Tue, 9 Dec 2014 01:34:23 -0800 Subject: [PATCH 0070/1152] doc: Minor makefile cleanup. Split out directory creation to leverage order only prerequisites. Signed-off-by: Jon A. Cruz Acked-by: Peter Hutterer Acked-by: Pekka Paalanen --- doc/doxygen/Makefile.am | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index f8d636e3..7276f5cf 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -22,22 +22,24 @@ scanned_src_files_server = \ # all-local below) dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") -xml/client/index.xml: $(scanned_src_files_client) wayland.doxygen - $(AM_V_GEN)$(MKDIR_P) xml/client && \ - (cat wayland.doxygen; \ +# Listing various directories that might need to be created. +alldirs := xml/client xml/server man/man3 + +xml/client/index.xml: $(scanned_src_files_client) wayland.doxygen | xml/client + $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/client"; \ echo "INPUT= $(scanned_src_files_client)"; \ ) | $(DOXYGEN) - -xml/server/index.xml: $(scanned_src_files_server) wayland.doxygen - $(AM_V_GEN)$(MKDIR_P) xml/server && \ - (cat wayland.doxygen; \ + +xml/server/index.xml: $(scanned_src_files_server) wayland.doxygen | xml/server + $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/server"; \ echo "INPUT= $(scanned_src_files_server)"; \ ) | $(DOXYGEN) - -man/man3/wl_display.3: $(scanned_src_files_client) $(scanned_src_files_server) +man/man3/wl_display.3: $(scanned_src_files_client) $(scanned_src_files_server) wayland.doxygen | man/man3 $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_MAN=YES"; \ echo "MAN_OUTPUT=man"; \ @@ -45,6 +47,10 @@ man/man3/wl_display.3: $(scanned_src_files_client) $(scanned_src_files_server) echo "INPUT= $^"; \ ) | $(DOXYGEN) - +# general rule to create one of the listed directories. +$(alldirs): + $(AM_V_GEN)$(MKDIR_P) $@ + # there is no man-local all-local: man/man3/wl_display.3 From 0b788154da926c635ca48628f46fac1d3c9eb5ca Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 9 Dec 2014 17:01:11 -0800 Subject: [PATCH 0071/1152] doc: fix doxygen->man command line It was telling it to scan the doxyfile as well as the C source, and listing some source files more than once. Reviewed-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- doc/doxygen/Makefile.am | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 7276f5cf..8d563f4f 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -17,6 +17,11 @@ scanned_src_files_server = \ $(top_srcdir)/src/wayland-server.h \ $(top_srcdir)/src/wayland-shm.c +scanned_src_files_man = \ + $(scanned_src_files_server) \ + $(top_srcdir)/src/wayland-client.c \ + $(top_srcdir)/src/wayland-client.h + # find all man/man3/wl_foo.3 pages # for this to work, we need to create them before the man target (hence # all-local below) @@ -39,12 +44,12 @@ xml/server/index.xml: $(scanned_src_files_server) wayland.doxygen | xml/server echo "INPUT= $(scanned_src_files_server)"; \ ) | $(DOXYGEN) - -man/man3/wl_display.3: $(scanned_src_files_client) $(scanned_src_files_server) wayland.doxygen | man/man3 +man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3 $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_MAN=YES"; \ echo "MAN_OUTPUT=man"; \ echo "JAVADOC_AUTOBRIEF=NO"; \ - echo "INPUT= $^"; \ + echo "INPUT= $(scanned_src_files_man)"; \ ) | $(DOXYGEN) - # general rule to create one of the listed directories. From c985a17988e4df48618b6687dfddfb18a94793e1 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 9 Dec 2014 17:01:12 -0800 Subject: [PATCH 0072/1152] doc: Split libwayland-client and -server into different pages This was suggested before to make it clearer that things like wl_display are different objects in each of them. I made these into two appendixes because the protocol spec was already an appendix. Reviewed-by: Bryce Harrington [Bryce requested minor changes, not yet here.] Acked-by: Pekka Paalanen --- doc/publican/Makefile.am | 1 - doc/publican/doxygen-to-publican.xsl | 28 ++++++++++++++++++++++------ doc/publican/sources/Library.xml | 27 --------------------------- doc/publican/sources/Wayland.xml | 3 ++- 4 files changed, 24 insertions(+), 35 deletions(-) delete mode 100644 doc/publican/sources/Library.xml diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 8ed3815c..c109795e 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -25,7 +25,6 @@ publican_sources = \ $(srcdir)/sources/Introduction.xml \ $(srcdir)/sources/Architecture.xml \ $(srcdir)/sources/Protocol.xml \ - $(srcdir)/sources/Library.xml \ $(srcdir)/sources/Compositors.xml \ $(srcdir)/sources/images/icon.svg \ $(srcdir)/sources/images/wayland-architecture.png \ diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index d8f3289d..53fc60fd 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -12,13 +12,29 @@ ]> ]]> -
+ sect-Library- <xsl:value-of select="$which"/> API - Following is the Wayland library classes for the - (libwayland-). - Note that most of the procedures are related with IPC, which is the main responsibility of - the library. + + + The open-source reference implementation of Wayland protocol is + split in two C libraries, libwayland-client and libwayland-server. Their + main responsibility is to handle the Inter-process communication + (IPC) with each other, therefore + guaranteeing the protocol objects marshaling and messages + synchronization. + + + + Following is the Wayland library classes for the + + (libwayland-). This appendix describes in detail + the library's methods and their helpers, aiming implementors who + are building a Wayland . @@ -36,7 +52,7 @@ -
+
diff --git a/doc/publican/sources/Library.xml b/doc/publican/sources/Library.xml deleted file mode 100644 index bc8c89ec..00000000 --- a/doc/publican/sources/Library.xml +++ /dev/null @@ -1,27 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - Wayland Library - - - The open-source reference implementation of Wayland protocol is split in two - C libraries, libwayland-server and - libwayland-client. Their main - responsibility is to handle the Inter-process communication - (IPC) with each other, therefore guaranteeing the - protocol objects marshaling and messages synchronization. - - - - This Chapter describes in detail each library's methods and their helpers, - aiming implementors who can use for building Wayland clients and servers; - respectively at and - . - - - - - diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/sources/Wayland.xml index 24a98767..bdf89300 100644 --- a/doc/publican/sources/Wayland.xml +++ b/doc/publican/sources/Wayland.xml @@ -12,6 +12,7 @@ - + + From 3f05c4ac4a747f5296f24424925eda292ccbe7d4 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 16 Dec 2014 19:23:02 -0800 Subject: [PATCH 0073/1152] doc: fix for parallel make Move the *_8h.xml files to a per-chapter temporary file so two chapters can be converted from doxygen at the same time. Tested with make -j 9. Reviewed-by: Bryce Harrington --- doc/publican/Makefile.am | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index c109795e..b4cfe82e 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -94,11 +94,12 @@ $(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(s # * use doxygen's combine.xslt to merge the xml files into one single file # * move wayland-_8h.xml back to its original location $(builddir)/en-US/%API.xml.tmp: $(doxydir)/xml/%/index.xml | $(builddir)/en-US - $(AM_V_at)mv $(doxydir)/xml/$*/wayland-$*_8h.xml \ - $(doxydir)/xml/ + $(AM_V_at)$(MKDIR_P) $(doxydir)/xml/$*/saved + $(AM_V_at)mv $(doxydir)/xml/$*/wayland-*_8h.xml \ + $(doxydir)/xml/$*/saved $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \ $(doxydir)/xml/$*/index.xml > $@ - $(AM_V_at)mv $(doxydir)/xml/wayland-$*_8h.xml \ + $(AM_V_at)mv $(doxydir)/xml/$*/saved/* \ $(doxydir)/xml/$* # WaylandClientAPI.xml: From 6e3ad249adbf527e70d89fdb7dd25e289929f1a2 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 16 Dec 2014 19:23:03 -0800 Subject: [PATCH 0074/1152] doc: Make it easier to add a new doxygen page The repetitive parts of generating the server and client documentation are merged, so it is easier to add another doxygen chapter: add a new line to $publican_sources in publican/Makefile.am, and a list of C source files to doxygen/Makefile.am. Reviewed-by: Bryce Harrington --- doc/doxygen/Makefile.am | 23 +++++++------------ doc/publican/Makefile.am | 34 +++++++++++----------------- doc/publican/doxygen-to-publican.xsl | 5 ++-- doc/publican/sources/Wayland.xml | 4 ++-- 4 files changed, 25 insertions(+), 41 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 8d563f4f..8c4618a8 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -1,24 +1,24 @@ -noinst_DATA = xml/client/index.xml xml/server/index.xml +noinst_DATA = xml/Client/index.xml xml/Server/index.xml dist_noinst_DATA = wayland.doxygen.in scanned_src_files_shared = \ $(top_srcdir)/src/wayland-util.c \ $(top_srcdir)/src/wayland-util.h -scanned_src_files_client = \ +scanned_src_files_Client = \ $(scanned_src_files_shared) \ $(top_srcdir)/src/wayland-client.c \ $(top_srcdir)/src/wayland-client.h -scanned_src_files_server = \ +scanned_src_files_Server = \ $(scanned_src_files_shared) \ $(top_srcdir)/src/wayland-server.c \ $(top_srcdir)/src/wayland-server.h \ $(top_srcdir)/src/wayland-shm.c scanned_src_files_man = \ - $(scanned_src_files_server) \ + $(scanned_src_files_Server) \ $(top_srcdir)/src/wayland-client.c \ $(top_srcdir)/src/wayland-client.h @@ -28,20 +28,13 @@ scanned_src_files_man = \ dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") # Listing various directories that might need to be created. -alldirs := xml/client xml/server man/man3 +alldirs := xml/Client xml/Server man/man3 -xml/client/index.xml: $(scanned_src_files_client) wayland.doxygen | xml/client +xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen | xml/% $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ - echo "XML_OUTPUT=xml/client"; \ - echo "INPUT= $(scanned_src_files_client)"; \ - ) | $(DOXYGEN) - - -xml/server/index.xml: $(scanned_src_files_server) wayland.doxygen | xml/server - $(AM_V_GEN)(cat wayland.doxygen; \ - echo "GENERATE_XML=YES"; \ - echo "XML_OUTPUT=xml/server"; \ - echo "INPUT= $(scanned_src_files_server)"; \ + echo "XML_OUTPUT=xml/$*"; \ + echo "INPUT= $(scanned_src_files_$*)"; \ ) | $(DOXYGEN) - man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3 diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index b4cfe82e..7f0ed1bc 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -8,9 +8,7 @@ # * ProtocolSpec.xml is generated from $(top_srcdir)/protocol/wayland.xml, # changed into docbook via XSLT and saved in $(builddir)/en-US/ # * ProtocolInterfaces.xml, same as above, uses a different XSLT -# * WaylandClientAPI.xml is generated from the doxygen output and saved in -# $(builddir)/en-US -# * WaylandServerAPI.xml is generated from the doxygen output and saved in +# * *API.xml is generated from the doxygen output and saved in # $(builddir)/en-US # * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US @@ -76,9 +74,11 @@ $(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images pubdir = $(docdir)/Wayland/en-US -publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \ - $(builddir)/en-US/ProtocolSpec.xml $(builddir)/en-US/ProtocolInterfaces.xml \ - $(builddir)/en-US/WaylandClientAPI.xml $(builddir)/en-US/WaylandServerAPI.xml +publican_targets = $(publican_sources:$(srcdir)/sources%=$(builddir)/en-US/%) \ + $(builddir)/en-US/ProtocolSpec.xml \ + $(builddir)/en-US/ProtocolInterfaces.xml \ + $(builddir)/en-US/ClientAPI.xml \ + $(builddir)/en-US/ServerAPI.xml # The Protocol.xml is purely generated and required before running publican $(builddir)/en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-to-docbook.xsl | $(builddir)/en-US @@ -92,31 +92,23 @@ $(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(s # * we don't want wayland-{server|client}_8h.xml to avoid duplicating output methods, # move it out of the way first. # * use doxygen's combine.xslt to merge the xml files into one single file +# * pipe that through the doxygen-to-publican stylesheet # * move wayland-_8h.xml back to its original location -$(builddir)/en-US/%API.xml.tmp: $(doxydir)/xml/%/index.xml | $(builddir)/en-US +$(builddir)/en-US/%API.xml: $(doxydir)/xml/%/index.xml $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US $(AM_V_at)$(MKDIR_P) $(doxydir)/xml/$*/saved $(AM_V_at)mv $(doxydir)/xml/$*/wayland-*_8h.xml \ $(doxydir)/xml/$*/saved $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \ - $(doxydir)/xml/$*/index.xml > $@ + $(doxydir)/xml/$*/index.xml | \ + $(XSLTPROC) --stringparam which $* \ + $(srcdir)/doxygen-to-publican.xsl - > $@ $(AM_V_at)mv $(doxydir)/xml/$*/saved/* \ $(doxydir)/xml/$* -# WaylandClientAPI.xml: -# merge doxygen xml files into one single file, then transform the combined XML file into docbook format -$(builddir)/en-US/WaylandClientAPI.xml: $(builddir)/en-US/clientAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US - $(AM_V_GEN)$(XSLTPROC) --stringparam which Client $(srcdir)/doxygen-to-publican.xsl \ - $(builddir)/en-US/clientAPI.xml.tmp > $@ - -# WaylandServerAPI.xml: see WaylandClientAPI.xml -$(builddir)/en-US/WaylandServerAPI.xml: $(builddir)/en-US/serverAPI.xml.tmp $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US - $(AM_V_GEN)$(XSLTPROC) --stringparam which Server $(srcdir)/doxygen-to-publican.xsl \ - $(builddir)/en-US/serverAPI.xml.tmp > $@ - # Copy the sources source files into en-US destination # This is required for out-of-source-tree build as publican does not allow us # to specify the location of the source code. -$(builddir)/en-US/%: $(srcdir)/sources/% $(builddir)/en-US/ProtocolSpec.xml $(builddir)/en-US/ProtocolInterfaces.xml $(builddir)/en-US/WaylandClientAPI.xml $(publican_sources) | $(builddir)/en-US/images +$(builddir)/en-US/%: $(srcdir)/sources/% $(publican_sources) | $(builddir)/en-US/images $(AM_V_GEN)cp -f $< $@ $(AM_V_at)chmod a+w $@ @@ -124,7 +116,7 @@ $(builddir)/en-US/%: $(srcdir)/sources/% $(builddir)/en-US/ProtocolSpec.xml $(bu $(alldirs): $(AM_V_GEN)$(MKDIR_P) $@ -CLEANFILES = $(builddir)/en-US/ProtocolSpec.xml $(builddir)/en-US/ProtocolInterfaces.xml $(builddir)/en-US/WaylandClientAPI.xml $(publican_targets) +CLEANFILES = $(publican_targets) clean-local: $(AM_V_at)rm -fr $(builddir)/en-US diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 53fc60fd..47bdc5a7 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -29,9 +29,8 @@ Following is the Wayland library classes for the - - (libwayland-). This appendix describes in detail + libwayland-. This appendix describes in detail the library's methods and their helpers, aiming implementors who are building a Wayland . diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/sources/Wayland.xml index bdf89300..5ae90bb2 100644 --- a/doc/publican/sources/Wayland.xml +++ b/doc/publican/sources/Wayland.xml @@ -12,7 +12,7 @@ - - + + From 75ec915da87acf3e75a408586ac8468a038b699a Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 16 Dec 2014 19:52:10 -0800 Subject: [PATCH 0075/1152] fixup doc: Make it easier to add a new doxygen page This supersedes the previous one and fixes a typo where a slash was missing. Reviewed-by: Pekka Paalanen --- doc/publican/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 7f0ed1bc..278da12f 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -74,7 +74,7 @@ $(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images pubdir = $(docdir)/Wayland/en-US -publican_targets = $(publican_sources:$(srcdir)/sources%=$(builddir)/en-US/%) \ +publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \ $(builddir)/en-US/ProtocolSpec.xml \ $(builddir)/en-US/ProtocolInterfaces.xml \ $(builddir)/en-US/ClientAPI.xml \ From dfc64f9ffe0ceecf8e93d6eba3fdb7b1165c9c43 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Thu, 18 Dec 2014 20:15:05 -0800 Subject: [PATCH 0076/1152] doc: Reduce the validation errors of the docbook input (this is different from previous version as it removes some broken and irrelevant changes to the protocol appendix). This removes all the validation errors except for missing link targets. You can test this by removing the --skip-validation from doc/publican/Makefile.am. Main changes are to avoid nesting commands. I also used in some places to reduce the amount of blank space. And the reference id's are prefixed with the chapter name to avoid collisions between libclient and libserver. PS: it would be useful if somebody who actually knows something about xslt would come up with a way to translate a block of text makde of commands unchanged, but add around plain text. Most of the difficulty is that doxygen's output is rather inconsistent here. Tested-by: Pekka Paalanen --- doc/publican/doxygen-to-publican.xsl | 44 +++++++------------ .../protocol-interfaces-to-docbook.xsl | 8 ++-- doc/publican/protocol-to-docbook.xsl | 4 +- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 47bdc5a7..5adbfa6c 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -37,20 +37,16 @@ - - - - - + + + Methods for the respective classes. - - + - @@ -60,7 +56,7 @@ - +
@@ -74,7 +70,7 @@ - + @@ -82,22 +78,18 @@ Returns: - + - - See also: - + See also: - - Since: - + Since: @@ -131,7 +123,7 @@ - + @@ -139,21 +131,19 @@ - - - - - + + + - + - - + + @@ -165,6 +155,6 @@ - + diff --git a/doc/publican/protocol-interfaces-to-docbook.xsl b/doc/publican/protocol-interfaces-to-docbook.xsl index fb1a8160..57b3139a 100644 --- a/doc/publican/protocol-interfaces-to-docbook.xsl +++ b/doc/publican/protocol-interfaces-to-docbook.xsl @@ -37,11 +37,13 @@ - - - - + + + + + diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 443228d8..a43c9fa7 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -95,9 +95,7 @@ Value: - - - + From 4abe5edf46f1b1417394c3186e2056673bc358d3 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Thu, 18 Dec 2014 20:15:06 -0800 Subject: [PATCH 0077/1152] doc: removed the word "interface" from the link names Just to make it slightly shorter. Also add a dash to the doxygen links to make them look a bit more alike. Tested-by: Pekka Paalanen --- doc/publican/doxygen-to-publican.xsl | 6 +++--- doc/publican/protocol-interfaces-to-docbook.xsl | 10 +++++----- doc/publican/protocol-to-docbook.xsl | 7 ++----- doc/publican/sources/Protocol.xml | 16 ++++++++-------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 5adbfa6c..0ed70302 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -70,7 +70,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -143,7 +143,7 @@ - + diff --git a/doc/publican/protocol-interfaces-to-docbook.xsl b/doc/publican/protocol-interfaces-to-docbook.xsl index 57b3139a..f68216d5 100644 --- a/doc/publican/protocol-interfaces-to-docbook.xsl +++ b/doc/publican/protocol-interfaces-to-docbook.xsl @@ -23,10 +23,10 @@ - Core interfaces: - - - + Core interfaces: + + + @@ -35,7 +35,7 @@ - + diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index a43c9fa7..354ff3ac 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -49,9 +49,7 @@ -
- protocol-spec-- - +
<xsl:value-of select="@name" /> <!-- only show summary if it exists --> @@ -103,8 +101,7 @@ <!-- Request/event list --> <xsl:template match="request|event|enum"> - <section> - <xsl:attribute name="id">protocol-spec-interface-<xsl:value-of select="../@name"/>-<xsl:value-of select="name()"/>-<xsl:value-of select="@name"/></xsl:attribute> + <section id="protocol-spec-{../@name}-{name()}-{@name}"> <title> <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> <xsl:if test="description/@summary"> diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index b79b6be1..5f3e8526 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -275,7 +275,7 @@ The compositor is a global object, advertised at connect time. </para> <para> - See <xref linkend="protocol-spec-interface-wl_compositor"/> for the + See <xref linkend="protocol-spec-wl_compositor"/> for the protocol description. </para> </section> @@ -287,7 +287,7 @@ cannot access other clients surfaces. </para> <para> - See <xref linkend="protocol-spec-interface-wl_surface"/> for the protocol + See <xref linkend="protocol-spec-wl_surface"/> for the protocol description. </para> </section> @@ -324,7 +324,7 @@ or triple clicks. </para> <para> - See <xref linkend="protocol-spec-interface-wl_seat"/> for the + See <xref linkend="protocol-spec-wl_seat"/> for the protocol description. </para> <para> @@ -383,7 +383,7 @@ comes and goes. </para> <para> - See <xref linkend="protocol-spec-interface-wl_output"/> for the protocol + See <xref linkend="protocol-spec-wl_output"/> for the protocol description. </para> <para> @@ -432,10 +432,10 @@ that implements copy-paste and drag-and-drop support. </para> <para> - See <xref linkend="protocol-spec-interface-wl_data_offer"/>, - <xref linkend="protocol-spec-interface-wl_data_source"/>, - <xref linkend="protocol-spec-interface-wl_data_device"/> and - <xref linkend="protocol-spec-interface-wl_data_device_manager"/> for + See <xref linkend="protocol-spec-wl_data_offer"/>, + <xref linkend="protocol-spec-wl_data_source"/>, + <xref linkend="protocol-spec-wl_data_device"/> and + <xref linkend="protocol-spec-wl_data_device_manager"/> for protocol descriptions. </para> <para> From f980a60038e06156d8462ed1c2881db456ad25c8 Mon Sep 17 00:00:00 2001 From: Bill Spitzak <spitzak@gmail.com> Date: Thu, 18 Dec 2014 20:15:07 -0800 Subject: [PATCH 0078/1152] doc: Each class in doxygen output is a section All the methods belonging to the class are listed with it, making it much easier to find them. I dumped all other functions into a section called "Functions" at the end. Tested-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- doc/publican/doxygen-to-publican.xsl | 36 ++++++++++++++++------------ 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 0ed70302..08a71e7b 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -36,17 +36,16 @@ 'SC', 'sc')"/>. </para> - <xsl:if test="/doxygen/compounddef[@kind='class']"> + <xsl:apply-templates select="/doxygen/compounddef[@kind='class']" /> + + <section id="{$which}-Functions"> + <title>Functions + - + - +
- Methods for the respective classes. - - - - @@ -104,6 +103,11 @@ + + + + + - - +
+ <xsl:value-of select="compoundname" /> <xsl:if test="normalize-space(briefdescription) != ''"> - <xsl:apply-templates select="briefdescription" /> </xsl:if> - </term> + - - - - + + + + + +
From 0d0a62c79a65c5961db5f108fc4bff84691f8f1c Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Thu, 18 Dec 2014 20:15:08 -0800 Subject: [PATCH 0079/1152] doc: Document structures and unions in addition to classes This provides targets for some of the doxygen links, and some of them have useful memberof function lists. Added some if/else statements to reduce validation errors. Tested-by: Pekka Paalanen --- doc/publican/doxygen-to-publican.xsl | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 08a71e7b..dfd47eed 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -36,13 +36,13 @@ 'SC', 'sc')"/>. - +
Functions - +
@@ -146,7 +146,6 @@ -
<xsl:value-of select="compoundname" /> @@ -154,13 +153,19 @@ - <xsl:apply-templates select="briefdescription" /> </xsl:if> - - - - - - + + + + + + + + + + + + +
-
From 2888e97d5ddf54eb8e90cb686df8ae1a016c0412 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Thu, 18 Dec 2014 20:15:10 -0800 Subject: [PATCH 0080/1152] doc: make itemized lists from doxygen work Not actually used currently but probably a good idea. Acked-by: Pekka Paalanen --- doc/publican/doxygen-to-publican.xsl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index dfd47eed..a1516280 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -103,6 +103,14 @@ + + + + + + + + From b7f9925abccd787b54148814057052bbd6368ba6 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Sat, 17 Jan 2015 03:39:05 -0800 Subject: [PATCH 0081/1152] configure.ac: bump version to 1.6.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 12dd94c7..02490028 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [6]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 434d797d273cb9a1c57e15902da6480d4c62fc83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 23 Jan 2015 16:21:13 +0800 Subject: [PATCH 0082/1152] protocol: Fix typo in wl_data_offer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f70c0261..ac1b62fc 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -440,7 +440,7 @@ file descriptor. The receiving client reads from the read end of the pipe until - EOF and the closes its end, at which point the transfer is + EOF and then closes its end, at which point the transfer is complete. From 5ce947bd9043c989e2caa4a6053e542b048a5718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 23 Jan 2015 16:21:14 +0800 Subject: [PATCH 0083/1152] protocol: Clarify selection data offer destruction requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify that a client receiving a wl_data_device.selection event must destroy the data_offer of the previous wl_data_device.selection event, if any. Signed-off-by: Jonas Ådahl --- protocol/wayland.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index ac1b62fc..2a498054 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -643,7 +643,9 @@ immediately before receiving keyboard focus and when a new selection is set while the client has keyboard focus. The data_offer is valid until a new data_offer or NULL is received - or until the client loses keyboard focus. + or until the client loses keyboard focus. The client must + destroy the previous selection data_offer, if any, upon receiving + this event. From ab3ee6f6d96c2e9adc3808975fdaf1727e5ff48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 23 Jan 2015 16:21:15 +0800 Subject: [PATCH 0084/1152] server: Use existing id variable when inserting created object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have the id variable there and it makes it slightly easier to read. Signed-off-by: Jonas Ådahl Reviewed-by: Bryce Harrington --- src/wayland-server.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index c845dd68..cde1eef9 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1313,11 +1313,10 @@ wl_resource_create(struct wl_client *client, resource->version = version; resource->dispatcher = NULL; - if (wl_map_insert_at(&client->objects, 0, resource->object.id, resource) < 0) { + if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid new id %d", - resource->object.id); + "invalid new id %d", id); free(resource); return NULL; } From 594ec7e6893db1b15178cc748b7027692acb7c2f Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:15 -0800 Subject: [PATCH 0085/1152] doc: add missing \memberof to wl_display_get_protocol_error Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- src/wayland-client.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 9e8bdfec..d1d21ca7 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1689,8 +1689,7 @@ wl_display_get_error(struct wl_display *display) return ret; } -/** - * Retrieves the information about a protocol error: +/** Retrieves the information about a protocol error: * * \param display The Wayland display * \param interface if not NULL, stores the interface where the error occurred @@ -1708,8 +1707,8 @@ wl_display_get_error(struct wl_display *display) * } * * ... - * - * \endcode + * \endcode + * \memberof wl_display */ WL_EXPORT uint32_t wl_display_get_protocol_error(struct wl_display *display, From 074e120cb3ec373b5594cc29280b4622d18c422d Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:16 -0800 Subject: [PATCH 0086/1152] doc: Remove deprecated functions from documentation Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- src/wayland-server.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index cde1eef9..7f7f187a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1330,7 +1330,7 @@ wl_log_set_handler_server(wl_log_func_t handler) wl_log_handler = handler; } -/* Deprecated functions below. */ +/** \cond */ /* Deprecated functions below. */ uint32_t wl_client_add_resource(struct wl_client *client, @@ -1427,6 +1427,8 @@ wl_display_remove_global(struct wl_display *display, struct wl_global *global) wl_global_destroy(global); } +/** \endcond */ + /** Add support for a wl_shm pixel format * * \param display The display object From d3770c0661f1c38ee3d0eecef32a4ffeee96907b Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:17 -0800 Subject: [PATCH 0087/1152] doc: Remove wl_map from documentation This object is only in wayland-private.h so it's methods should not be in the documentation. Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- src/wayland-util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland-util.c b/src/wayland-util.c index b099882b..db51ebb1 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -149,6 +149,8 @@ wl_array_copy(struct wl_array *array, struct wl_array *source) return 0; } +/** \cond */ + union map_entry { uintptr_t next; void *data; @@ -361,6 +363,8 @@ wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) for_each_helper(&map->server_entries, func, data); } +/** \endcond */ + static void wl_log_stderr_handler(const char *fmt, va_list arg) { From 1f39fbf8d282b3c70e8a78a37a0b2cf7ac863763 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:18 -0800 Subject: [PATCH 0088/1152] doc: made functions taking wl_event_queue arg belong to wl_event_queue The fact that these functions take both a display and queue argument is I think historical, and they really are methods on the queue. Also added some docs for wl_display_prepare_read_queue. Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- src/wayland-client.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index d1d21ca7..757d69cd 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -260,7 +260,7 @@ wl_event_queue_destroy(struct wl_event_queue *queue) * \return A new event queue associated with this display or NULL on * failure. * - * \memberof wl_display + * \memberof wl_event_queue */ WL_EXPORT struct wl_event_queue * wl_display_create_queue(struct wl_display *display) @@ -915,7 +915,7 @@ static const struct wl_callback_listener sync_listener = { * with calling wl_display_prepare_read() and wl_display_read_events()) * * \sa wl_display_roundtrip() - * \memberof wl_display + * \memberof wl_event_queue */ WL_EXPORT int wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue) @@ -1336,6 +1336,21 @@ err: return -1; } +/** Prepare to read events from the display to this queue + * + * \param display The display context object + * \param queue The event queue to use + * \return 0 on success or -1 if event queue was not empty + * + * Atomically makes sure the queue is empty and stops any other thread + * from placing events into this (or any) queue. Caller must + * eventually call either wl_display_cancel_read() or + * wl_display_read_events(), usually after waiting for the + * display fd to become ready for reading, to release the lock. + * + * \sa wl_display_prepare_read + * \memberof wl_event_queue + */ WL_EXPORT int wl_display_prepare_read_queue(struct wl_display *display, struct wl_event_queue *queue) @@ -1497,7 +1512,7 @@ wl_display_cancel_read(struct wl_display *display) * \sa wl_display_dispatch(), wl_display_dispatch_pending(), * wl_display_dispatch_queue_pending() * - * \memberof wl_display + * \memberof wl_event_queue */ WL_EXPORT int wl_display_dispatch_queue(struct wl_display *display, @@ -1569,7 +1584,7 @@ wl_display_dispatch_queue(struct wl_display *display, * event queue. On failure -1 is returned and errno set appropriately. * If there are no events queued, this function returns immediately. * - * \memberof wl_display + * \memberof wl_event_queue * \since 1.0.2 */ WL_EXPORT int From be8064d2d4a94df010e1909eddb7e57c39babc61 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:20 -0800 Subject: [PATCH 0089/1152] doc: compress the lists in the protocol docs some Use simpara to remove the blank lines, and put the type/value and the comment into the same line. Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- doc/publican/protocol-to-docbook.xsl | 30 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 354ff3ac..723f5e6f 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -81,20 +81,32 @@
- - + + - - Type: - - - Value: - + + () - + + + + + + + + + + + + + + + + + From d90fd15ee4950f1ea5849e784dc592466de7b90b Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:21 -0800 Subject: [PATCH 0090/1152] doc: Add object types and links to arguments int protocol documentation This makes it a lot easier to figure out what is going on! Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- doc/publican/protocol-to-docbook.xsl | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 723f5e6f..ca1308f1 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -111,6 +111,41 @@
+ + + + + + + + + + + + + + + + + + + + + + + + id for the new + + + + + + + + + + +
From 6750538455a5bfdbaff3635233c227670ec9b27f Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 2 Jan 2015 18:29:22 -0800 Subject: [PATCH 0091/1152] doc: remove redundant subtitles Put the argument lists next to the event/message title, which I think makes it a lot easier to understand, and remove redundant "values" title from enumerations. Reviewed-by: Derek Foreman Reviewed-by: Bryce Harrington --- doc/publican/protocol-to-docbook.xsl | 38 ++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index ca1308f1..a886b7f9 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -147,7 +147,27 @@ - + +
+ + <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> + <xsl:if test="description/@summary"> + - <xsl:value-of select="description/@summary" /> + </xsl:if> + + + + + + + + + +
+
+ + +
<xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> @@ -158,20 +178,12 @@ <xsl:call-template name="break"> <xsl:with-param name="text" select="description" /> </xsl:call-template> - <xsl:if test="arg"> - <variablelist> - <title><xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> arguments - - - - - - <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> values - - - + + +
+ From a1a6aa54aa4db524ffd2fccf606acfe0a914a0b9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Sat, 24 Jan 2015 09:24:23 -0600 Subject: [PATCH 0092/1152] cosmetic: Move the deprecated functions back to the end of the file There are functions below the "Deprecated functions below" comment that are not deprecated. Move the deprecated functions back down, and add a comment at the end of the file to try to keep this from happening again. Signed-off-by: Derek Foreman --- src/wayland-server.c | 105 ++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 7f7f187a..c03e3513 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1330,6 +1330,58 @@ wl_log_set_handler_server(wl_log_func_t handler) wl_log_handler = handler; } +/** Add support for a wl_shm pixel format + * + * \param display The display object + * \param format The wl_shm pixel format to advertise + * \return A pointer to the wl_shm format that was added to the list + * or NULL if adding it to the list failed. + * + * Add the specified wl_shm format to the list of formats the wl_shm + * object advertises when a client binds to it. Adding a format to + * the list means that clients will know that the compositor supports + * this format and may use it for creating wl_shm buffers. The + * compositor must be able to handle the pixel format when a client + * requests it. + * + * The compositor by default supports WL_SHM_FORMAT_ARGB8888 and + * WL_SHM_FORMAT_XRGB8888. + * + * \memberof wl_display + */ +WL_EXPORT uint32_t * +wl_display_add_shm_format(struct wl_display *display, uint32_t format) +{ + uint32_t *p = NULL; + + p = wl_array_add(&display->additional_shm_formats, sizeof *p); + + if (p != NULL) + *p = format; + return p; +} + +/** + * Get list of additional wl_shm pixel formats + * + * \param display The display object + * + * This function returns the list of addition wl_shm pixel formats + * that the compositor supports. WL_SHM_FORMAT_ARGB8888 and + * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the + * array, but all formats added through wl_display_add_shm_format() + * will be in the array. + * + * \sa wl_display_add_shm_format() + * + * \memberof wl_display + */ +struct wl_array * +wl_display_get_additional_shm_formats(struct wl_display *display) +{ + return &display->additional_shm_formats; +} + /** \cond */ /* Deprecated functions below. */ uint32_t @@ -1429,54 +1481,7 @@ wl_display_remove_global(struct wl_display *display, struct wl_global *global) /** \endcond */ -/** Add support for a wl_shm pixel format - * - * \param display The display object - * \param format The wl_shm pixel format to advertise - * \return A pointer to the wl_shm format that was added to the list - * or NULL if adding it to the list failed. - * - * Add the specified wl_shm format to the list of formats the wl_shm - * object advertises when a client binds to it. Adding a format to - * the list means that clients will know that the compositor supports - * this format and may use it for creating wl_shm buffers. The - * compositor must be able to handle the pixel format when a client - * requests it. - * - * The compositor by default supports WL_SHM_FORMAT_ARGB8888 and - * WL_SHM_FORMAT_XRGB8888. - * - * \memberof wl_display +/* Functions at the end of this file are deprecated. Instead of adding new + * code here, add it before the comment above that states: + * Deprecated functions below. */ -WL_EXPORT uint32_t * -wl_display_add_shm_format(struct wl_display *display, uint32_t format) -{ - uint32_t *p = NULL; - - p = wl_array_add(&display->additional_shm_formats, sizeof *p); - - if (p != NULL) - *p = format; - return p; -} - -/** - * Get list of additional wl_shm pixel formats - * - * \param display The display object - * - * This function returns the list of addition wl_shm pixel formats - * that the compositor supports. WL_SHM_FORMAT_ARGB8888 and - * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the - * array, but all formats added through wl_display_add_shm_format() - * will be in the array. - * - * \sa wl_display_add_shm_format() - * - * \memberof wl_display - */ -struct wl_array * -wl_display_get_additional_shm_formats(struct wl_display *display) -{ - return &display->additional_shm_formats; -} From 71c37eb91aea311b3d5f66e944f7b7521c42189a Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Mon, 26 Jan 2015 11:30:57 -0800 Subject: [PATCH 0093/1152] cosmetic: Cleanup trailing whitespace --- src/wayland-server.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index c03e3513..05586340 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -358,7 +358,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) * socket later - typically when the compositor has handled all * requests and goes back to block in the event loop. This function * flushes all queued up events for a client immediately. - * + * * \memberof wl_client */ WL_EXPORT void @@ -371,7 +371,7 @@ wl_client_flush(struct wl_client *client) * * \param client The client object * \return The display object the client is associated with. - * + * * \memberof wl_client */ WL_EXPORT struct wl_display * @@ -402,7 +402,7 @@ bind_display(struct wl_client *client, struct wl_display *display); * WAYLAND_SOCKET environment variable on the client side. * * On failure this function sets errno accordingly and returns NULL. - * + * * \memberof wl_display */ WL_EXPORT struct wl_client * @@ -472,7 +472,7 @@ err_client: * then connects using socketpair(), this function will return the * credentials for the compositor. The credentials for the socketpair * are set at creation time in the compositor. - * + * * \memberof wl_client */ WL_EXPORT void @@ -494,8 +494,8 @@ wl_client_get_credentials(struct wl_client *client, * \return The object or NULL if there is not object for the given ID * * This looks up an object in the client object name space by its - * object ID. - * + * object ID. + * * \memberof wl_client */ WL_EXPORT struct wl_resource * @@ -583,12 +583,12 @@ wl_resource_find_for_client(struct wl_list *list, struct wl_client *client) if (client == NULL) return NULL; - wl_list_for_each(resource, list, link) { - if (resource->client == client) - return resource; - } + wl_list_for_each(resource, list, link) { + if (resource->client == client) + return resource; + } - return NULL; + return NULL; } WL_EXPORT struct wl_client * @@ -951,7 +951,7 @@ wl_global_destroy(struct wl_global *global) * * This function returns the most recent serial number, but does not * increment it. - * + * * \memberof wl_display */ WL_EXPORT uint32_t @@ -966,7 +966,7 @@ wl_display_get_serial(struct wl_display *display) * * This function increments the display serial number and returns the * new value. - * + * * \memberof wl_display */ WL_EXPORT uint32_t @@ -1371,9 +1371,9 @@ wl_display_add_shm_format(struct wl_display *display, uint32_t format) * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the * array, but all formats added through wl_display_add_shm_format() * will be in the array. - * + * * \sa wl_display_add_shm_format() - * + * * \memberof wl_display */ struct wl_array * From 5409187ed01dac8b3dd77c099a1ba8a5303062d1 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 23 Jan 2015 17:41:06 -0800 Subject: [PATCH 0094/1152] doc: there is no need to move the _8h files The current xslt skips all the data that is in them, so it is ok if they are included. Reviewed-by: "Jon A. Cruz" Reviewed-by: Bryce Harrington --- doc/publican/Makefile.am | 8 -------- 1 file changed, 8 deletions(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 278da12f..332399df 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -89,21 +89,13 @@ $(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(s $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-interfaces-to-docbook.xsl \ $(top_srcdir)/protocol/wayland.xml > $@ -# * we don't want wayland-{server|client}_8h.xml to avoid duplicating output methods, -# move it out of the way first. # * use doxygen's combine.xslt to merge the xml files into one single file # * pipe that through the doxygen-to-publican stylesheet -# * move wayland-_8h.xml back to its original location $(builddir)/en-US/%API.xml: $(doxydir)/xml/%/index.xml $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US - $(AM_V_at)$(MKDIR_P) $(doxydir)/xml/$*/saved - $(AM_V_at)mv $(doxydir)/xml/$*/wayland-*_8h.xml \ - $(doxydir)/xml/$*/saved $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \ $(doxydir)/xml/$*/index.xml | \ $(XSLTPROC) --stringparam which $* \ $(srcdir)/doxygen-to-publican.xsl - > $@ - $(AM_V_at)mv $(doxydir)/xml/$*/saved/* \ - $(doxydir)/xml/$* # Copy the sources source files into en-US destination # This is required for out-of-source-tree build as publican does not allow us From ed57d6d43889ebb4835ee04b1ea98fbda0548786 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 23 Jan 2015 17:41:07 -0800 Subject: [PATCH 0095/1152] doc: Add macros and typedefs to the documentation If somebody bothered to put a doxygen comment in for a macro or typedef, make it appear in the pages. This produces documentation for wl_container_of and wl_dispatcher_func_t from the _8h files. Reviewed-by: "Jon A. Cruz" Reviewed-by: Bryce Harrington --- doc/publican/doxygen-to-publican.xsl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index a1516280..cbcb2817 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -134,7 +134,8 @@ - + From 284da98a3c11983c3fb4af436f07de0186c56710 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Fri, 23 Jan 2015 17:41:08 -0800 Subject: [PATCH 0096/1152] doc: Put a dash between type/enum value and description This was suggested by Derek Foreman, I think it looks better Reviewed-by: Bryce Harrington --- doc/publican/protocol-to-docbook.xsl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index a886b7f9..7b45969e 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -87,9 +87,9 @@ - () + - + - @@ -104,7 +104,7 @@ - + - @@ -121,7 +121,7 @@ - + - @@ -139,7 +139,7 @@ - + - From 2eeb2cbc52e0729c78e8dde49d9d80f8faca1d6c Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 9 Jan 2015 16:05:11 -0800 Subject: [PATCH 0097/1152] tests: Fix typo "evnironment" Signed-off-by: Bryce Harrington Reviewed-by: Marek Chalupa --- tests/test-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 753617fa..9abf22f7 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -50,7 +50,7 @@ int leak_check_enabled; /* when this var is set to 0, every call to test_set_timeout() is * suppressed - handy when debugging the test. Can be set by - * WAYLAND_TEST_NO_TIMEOUTS evnironment var */ + * WAYLAND_TEST_NO_TIMEOUTS environment variable. */ static int timeouts_enabled = 1; /* set to one if the output goes to the terminal */ From 9386e2be275878ba7ee68bcd65ce3f130c3fe3b0 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 9 Jan 2015 16:05:12 -0800 Subject: [PATCH 0098/1152] tests: Correct return code handling Reviewed-by: Marek Chalupa Signed-off-by: Bryce Harrington --- tests/test-runner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 9abf22f7..48e9a227 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -255,13 +255,13 @@ is_debugger_attached(void) { int status; int rc; - int pid = fork(); + pid_t pid = fork(); if (pid == -1) return 0; if (pid == 0) { - int ppid = getppid(); + pid_t ppid = getppid(); if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0) { waitpid(ppid, NULL, 0); ptrace(PTRACE_CONT, NULL, NULL); From e3dc9a7af6f8f88ff7503bc3a70178e47802868d Mon Sep 17 00:00:00 2001 From: Mariusz Ceier Date: Mon, 15 Dec 2014 11:33:53 +0100 Subject: [PATCH 0099/1152] tests: C++ compilation test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test includes one of wayland headers, which produced error with C++ compiler. C compiler can't be used for this test, because it issues only a warning[1] and only when wayland headers are not installed in system headers path (/usr/include). [1] wayland-server-protocol.h:201:2: warning: implicit declaration of function ‘wl_resource_post_event’ [daniels: Merged in Marek's follow-up to check for a C++ compiler.] Signed-off-by: Mariusz Ceier Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- Makefile.am | 8 ++++++++ configure.ac | 12 ++++++++++++ tests/cpp-compile-test.cpp | 5 +++++ 3 files changed, 25 insertions(+) create mode 100644 tests/cpp-compile-test.cpp diff --git a/Makefile.am b/Makefile.am index 1551762a..43b741a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,6 +130,10 @@ TESTS = \ resources-test \ message-test +if ENABLE_CPP_TEST +TESTS += cpp-compile-test +endif + check_PROGRAMS = \ $(TESTS) \ exec-fd-leak-checker @@ -181,6 +185,10 @@ resources_test_LDADD = libtest-runner.la message_test_SOURCES = tests/message-test.c message_test_LDADD = libtest-runner.la +if ENABLE_CPP_TEST +cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp +endif + fixed_benchmark_SOURCES = tests/fixed-benchmark.c fixed_benchmark_LDADD = libtest-runner.la diff --git a/configure.ac b/configure.ac index 02490028..e749b006 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,18 @@ AM_SILENT_RULES([yes]) # Check for programs AC_PROG_CC +AC_PROG_CXX + +# check if we have C++ compiler. This is hacky workaround, +# for a reason why it is this way see +# http://lists.gnu.org/archive/html/bug-autoconf/2010-05/msg00001.html +have_cpp_compiler=yes + +if ! which "$CXX" &>/dev/null; then + have_cpp_compiler=no +fi + +AM_CONDITIONAL(ENABLE_CPP_TEST, test "x$have_cpp_compiler" = "xyes") # Initialize libtool LT_PREREQ([2.2]) diff --git a/tests/cpp-compile-test.cpp b/tests/cpp-compile-test.cpp new file mode 100644 index 00000000..1e84e637 --- /dev/null +++ b/tests/cpp-compile-test.cpp @@ -0,0 +1,5 @@ +/* This source should compile fine with C++ compiler */ +#include "wayland-server-protocol.h" + +int main() { return 0; } + From 6197f32cadc82d62a3641385098fe5ffebc147d6 Mon Sep 17 00:00:00 2001 From: Mariusz Ceier Date: Mon, 15 Dec 2014 12:48:38 +0100 Subject: [PATCH 0100/1152] scanner: Fix header generation for server protocols Server protocols headers should include wayland-server.h, instead of wayland-util.h. Otherwise they're not useable with C++ compiler unless wayland-server.h was included earlier. Signed-off-by: Mariusz Ceier Reviewed-by: Daniel Stone --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index ca03c57c..1f1e59a7 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1002,7 +1002,7 @@ emit_header(struct protocol *protocol, enum side side) "struct wl_resource;\n\n", protocol->uppercase_name, s, protocol->uppercase_name, s, - (side == SERVER) ? "wayland-util.h" : "wayland-client.h"); + (side == SERVER) ? "wayland-server.h" : "wayland-client.h"); wl_list_for_each(i, &protocol->interface_list, link) printf("struct %s;\n", i->name); From d8e72f98f21b70ac8ae6bcf6e7594c7e656773f4 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:00 +0100 Subject: [PATCH 0101/1152] test-runner: move leak checking into function 1) now we can use it in the test-compositor 2) it looks better Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- tests/test-runner.c | 54 +++++++++++++++++++++++++++++---------------- tests/test-runner.h | 6 +++++ 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 48e9a227..2e6ad338 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -149,15 +149,41 @@ sigalrm_handler(int signum) abort(); } +int +get_current_alloc_num(void) +{ + return num_alloc; +} + +void +check_leaks(int supposed_alloc, int supposed_fds) +{ + int num_fds; + + if (leak_check_enabled) { + if (supposed_alloc != num_alloc) { + fprintf(stderr, "Memory leak detected in test. " + "Allocated %d blocks, unfreed %d\n", num_alloc, + num_alloc - supposed_alloc); + abort(); + } + + num_fds = count_open_fds(); + if (supposed_fds != num_fds) { + fprintf(stderr, "fd leak detected in test. " + "Opened %d files, unclosed %d\n", num_fds, + num_fds - supposed_fds); + abort(); + } + } +} + static void run_test(const struct test *t) { - int cur_alloc = num_alloc; - int cur_fds, num_fds; + int cur_alloc, cur_fds; struct sigaction sa; - cur_fds = count_open_fds(); - if (timeouts_enabled) { sa.sa_handler = sigalrm_handler; sa.sa_flags = 0; @@ -165,27 +191,17 @@ run_test(const struct test *t) assert(sigaction(SIGALRM, &sa, NULL) == 0); } + cur_alloc = get_current_alloc_num(); + cur_fds = count_open_fds(); + t->run(); /* turn off timeout (if any) after test completition */ if (timeouts_enabled) alarm(0); - if (leak_check_enabled) { - if (cur_alloc != num_alloc) { - fprintf(stderr, "Memory leak detected in test. " - "Allocated %d blocks, unfreed %d\n", num_alloc, - num_alloc - cur_alloc); - abort(); - } - num_fds = count_open_fds(); - if (cur_fds != num_fds) { - fprintf(stderr, "fd leak detected in test. " - "Opened %d files, unclosed %d\n", num_fds, - num_fds - cur_fds); - abort(); - } - } + check_leaks(cur_alloc, cur_fds); + exit(EXIT_SUCCESS); } diff --git a/tests/test-runner.h b/tests/test-runner.h index 0e035304..5963ab62 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -39,6 +39,12 @@ count_open_fds(void); void exec_fd_leak_check(int nr_expected_fds); /* never returns */ +int +get_current_alloc_num(void); + +void +check_leaks(int supposed_allocs, int supposed_fds); + /* * set/reset the timeout in seconds. The timeout starts * at the point of invoking this function From 9ef027757110684f659e2698dc3382c96b9ab9e7 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:01 +0100 Subject: [PATCH 0102/1152] test-compositor: extend leak checks into clients Run leak checks also on clients of test-compositor. Checking leaks in memory is the same as in normal TEST. Checking file descriptor leaks is slightly more complex, as we pass an open file descriptor in the WAYLAND_SOCKET environment variable, which will be consumed by a client calling wl_display_connect(), but otherwise remain unused. We manage this accounting by checking if the environment variable has been unset by wl_display_connect() as it consumes the socket. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone [daniels: squashed counter-proposal patch to simplify fd leak checking, plus Bill's counter-counter-proposal, and reworded log.] --- tests/test-compositor.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 6f86a857..da2a55fd 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -33,6 +33,7 @@ #define WL_HIDE_DEPRECATED +#include "test-runner.h" #include "test-compositor.h" /* --- Protocol --- */ @@ -135,6 +136,7 @@ static void run_client(void (*client_main)(void), int wayland_sock, int client_pipe) { char s[8]; + int cur_alloc, cur_fds; int can_continue = 0; /* Wait until display signals that client can continue */ @@ -147,7 +149,20 @@ run_client(void (*client_main)(void), int wayland_sock, int client_pipe) snprintf(s, sizeof s, "%d", wayland_sock); setenv("WAYLAND_SOCKET", s, 0); + cur_alloc = get_current_alloc_num(); + cur_fds = count_open_fds(); + client_main(); + + /* Clients using wl_display_connect() will end up closing the socket + * passed in through the WAYLAND_SOCKET environment variable. When + * doing this, it clears the environment variable, so if it's been + * unset, then we assume the client consumed the file descriptor and + * do not count it towards leak checking. */ + if (!getenv("WAYLAND_SOCKET")) + cur_fds--; + + check_leaks(cur_alloc, cur_fds); } static struct client_info * From d1855797d33f0153ccf2c775d62b731f25b2625f Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:02 +0100 Subject: [PATCH 0103/1152] tests: add tests for leak check in clients Sanity tests for leak checks in clients of test compositor and also check if the test-compositor itself is not leaking anything. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- tests/display-test.c | 17 ++++++++++ tests/sanity-test.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index f9889a88..48c4cb9b 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -80,6 +80,23 @@ TEST(display_destroy_listener) assert(b.done); } +/* Fake 'client' which does not use wl_display_connect, and thus leaves the + * file descriptor passed through WAYLAND_SOCKET intact. This should not + * trigger an assertion in the leak check. */ +static void +empty_client(void) +{ + return; +} + +TEST(tc_leaks_tests) +{ + struct display *d = display_create(); + client_create(d, empty_client); + display_run(d); + display_destroy(d); +} + static void registry_handle_globals(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index bd3f70ca..a61dc99e 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -95,6 +95,22 @@ FAIL_TEST(sanity_malloc_indirect) /* not freeing array, must leak */ } +FAIL_TEST(tc_client_memory_leaks) +{ + struct display *d = display_create(); + client_create(d, sanity_malloc_direct); + display_run(d); + display_destroy(d); +} + +FAIL_TEST(tc_client_memory_leaks2) +{ + struct display *d = display_create(); + client_create(d, sanity_malloc_indirect); + display_run(d); + display_destroy(d); +} + FAIL_TEST(sanity_fd_leak) { int fd[2]; @@ -129,6 +145,65 @@ TEST(sanity_fd_exec) exec_fd_leak_check(nr_fds + 2); } +static void +sanity_fd_no_leak(void) +{ + int fd[2]; + + assert(leak_check_enabled); + + /* leak 2 file descriptors */ + if (pipe(fd) < 0) + exit(EXIT_SUCCESS); /* failed to fail */ + + close(fd[0]); + close(fd[1]); +} + +static void +sanity_client_no_leak(void) +{ + struct wl_display *display = wl_display_connect(NULL); + assert(display); + + wl_display_disconnect(display); +} + +TEST(tc_client_no_fd_leaks) +{ + struct display *d = display_create(); + + /* Client which does not consume the WAYLAND_DISPLAY socket. */ + client_create(d, sanity_fd_no_leak); + display_run(d); + + /* Client which does consume the WAYLAND_DISPLAY socket. */ + client_create(d, sanity_client_no_leak); + display_run(d); + + display_destroy(d); +} + +FAIL_TEST(tc_client_fd_leaks) +{ + struct display *d = display_create(); + + client_create(d, sanity_fd_leak); + display_run(d); + + display_destroy(d); +} + +FAIL_TEST(tc_client_fd_leaks_exec) +{ + struct display *d = display_create(); + + client_create(d, sanity_fd_leak); + display_run(d); + + display_destroy(d); +} + FAIL_TEST(timeout_tst) { test_set_timeout(1); From 2e20270280756cbf7387d5e4269e5c9c7c8a0e5b Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:03 +0100 Subject: [PATCH 0104/1152] connection-test: add tests for closure leaks When we destroy closure, we are leaking memory sometimes. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- tests/connection-test.c | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/connection-test.c b/tests/connection-test.c index 4497128f..d34e9a50 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -31,9 +31,11 @@ #include #include #include +#include #include "wayland-private.h" #include "test-runner.h" +#include "test-compositor.h" static const char message[] = "Hello, world"; @@ -571,3 +573,80 @@ TEST(invoke_closure) { marshal_helper("suu", suu_handler, "foo", 500, 404040); } + +static void +leak_closure(void) +{ + struct wl_callback *cb; + struct pollfd pfd; + struct client *c = client_connect(); + + cb = wl_display_sync(c->wl_display); + assert(cb); + assert(wl_display_flush(c->wl_display) > 0); + + /* we don't need it, it is referenced */ + wl_callback_destroy(cb); + + pfd.fd = wl_display_get_fd(c->wl_display); + pfd.events = POLLIN; + + test_set_timeout(2); + assert(poll(&pfd, 1, -1) == 1); + + /* read events, but do not dispatch them */ + assert(wl_display_prepare_read(c->wl_display) == 0); + assert(wl_display_read_events(c->wl_display) == 0); + + /* + * now we have wl_callback.done and wl_display.delete_id queued; + * if we now release the queue (in wl_display_disconnect()) + * we should not leak memory + */ + + client_disconnect(c); +} + +TEST(closure_leaks) +{ + struct display *d = display_create(); + + client_create(d, leak_closure); + display_run(d); + + display_destroy(d); +} + +static void +leak_after_error(void) +{ + struct client *c = client_connect(); + + /* this should return -1, because we'll send error + * from server. */ + assert(stop_display(c, 1) == -1); + assert(wl_display_dispatch_pending(c->wl_display) == -1); + assert(wl_display_get_error(c->wl_display) == ENOMEM); + + /* after we got error, we have display_resume event + * in the queue. It should be freed in wl_display_disconnect(). + * Let's see! */ + + wl_proxy_destroy((struct wl_proxy *) c->tc); + wl_display_disconnect(c->wl_display); + free(c); +} + +TEST(closure_leaks_after_error) +{ + struct display *d = display_create(); + struct client_info *cl; + + cl = client_create(d, leak_after_error); + display_run(d); + + wl_client_post_no_memory(cl->wl_client); + display_resume(d); + + display_destroy(d); +} From 73cb90763ce17eab9b066c5916a367e243e538c9 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:04 +0100 Subject: [PATCH 0105/1152] client: release display queue in wl_display_disconnect() Don't leak events, not even on exit Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- src/wayland-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 757d69cd..7a462aab 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -864,6 +864,7 @@ wl_display_disconnect(struct wl_display *display) wl_connection_destroy(display->connection); wl_map_release(&display->objects); wl_event_queue_release(&display->default_queue); + wl_event_queue_release(&display->display_queue); pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); close(display->fd); From 5c70c031903352530f701ca4badf4be1763984a4 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:05 +0100 Subject: [PATCH 0106/1152] client: unref or destroy proxy when releasing queue When we release event queue with queued events, we can leak proxies in some cases. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- src/wayland-client.c | 103 +++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 7a462aab..0f1405c0 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -217,15 +217,59 @@ wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) queue->display = display; } +static void +decrease_closure_args_refcount(struct wl_closure *closure) +{ + const char *signature; + struct argument_details arg; + int i, count; + struct wl_proxy *proxy; + + signature = closure->message->signature; + count = arg_count_for_signature(signature); + for (i = 0; i < count; i++) { + signature = get_next_argument(signature, &arg); + switch (arg.type) { + case 'n': + case 'o': + proxy = (struct wl_proxy *) closure->args[i].o; + if (proxy) { + if (proxy->flags & WL_PROXY_FLAG_DESTROYED) + closure->args[i].o = NULL; + + proxy->refcount--; + if (!proxy->refcount) + free(proxy); + } + break; + default: + break; + } + } +} + +void +proxy_destroy(struct wl_proxy *proxy); + static void wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; + struct wl_proxy *proxy; while (!wl_list_empty(&queue->event_list)) { closure = container_of(queue->event_list.next, struct wl_closure, link); wl_list_remove(&closure->link); + + decrease_closure_args_refcount(closure); + + proxy = closure->proxy; + if (proxy->refcount == 1) + proxy_destroy(proxy); + else + --proxy->refcount; + wl_closure_destroy(closure); } } @@ -355,19 +399,9 @@ wl_proxy_create_for_id(struct wl_proxy *factory, return proxy; } -/** Destroy a proxy object - * - * \param proxy The proxy to be destroyed - * - * \memberof wl_proxy - */ -WL_EXPORT void -wl_proxy_destroy(struct wl_proxy *proxy) +void +proxy_destroy(struct wl_proxy *proxy) { - struct wl_display *display = proxy->display; - - pthread_mutex_lock(&display->mutex); - if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) wl_map_remove(&proxy->display->objects, proxy->object.id); else if (proxy->object.id < WL_SERVER_ID_START) @@ -383,7 +417,21 @@ wl_proxy_destroy(struct wl_proxy *proxy) proxy->refcount--; if (!proxy->refcount) free(proxy); +} +/** Destroy a proxy object + * + * \param proxy The proxy to be destroyed + * + * \memberof wl_proxy + */ +WL_EXPORT void +wl_proxy_destroy(struct wl_proxy *proxy) +{ + struct wl_display *display = proxy->display; + + pthread_mutex_lock(&display->mutex); + proxy_destroy(proxy); pthread_mutex_unlock(&display->mutex); } @@ -1076,37 +1124,6 @@ queue_event(struct wl_display *display, int len) return size; } -static void -decrease_closure_args_refcount(struct wl_closure *closure) -{ - const char *signature; - struct argument_details arg; - int i, count; - struct wl_proxy *proxy; - - signature = closure->message->signature; - count = arg_count_for_signature(signature); - for (i = 0; i < count; i++) { - signature = get_next_argument(signature, &arg); - switch (arg.type) { - case 'n': - case 'o': - proxy = (struct wl_proxy *) closure->args[i].o; - if (proxy) { - if (proxy->flags & WL_PROXY_FLAG_DESTROYED) - closure->args[i].o = NULL; - - proxy->refcount--; - if (!proxy->refcount) - free(proxy); - } - break; - default: - break; - } - } -} - static void dispatch_event(struct wl_display *display, struct wl_event_queue *queue) { From 68c11c48c0f2bff69a10af503238cbf5d07a5df0 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:06 +0100 Subject: [PATCH 0107/1152] tests: add possibility to disable leak check for single test In tests that are using external libraries (i. e. pthread) we can get failure because of leaks in the external library. Until we have some better solution (if ever), let these (and only these) tests to disable leak checks. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- tests/sanity-test.c | 13 +++++++++++++ tests/test-runner.c | 2 ++ tests/test-runner.h | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index a61dc99e..b5a6fae3 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -81,6 +81,19 @@ FAIL_TEST(sanity_malloc_direct) free(NULL); /* NULL must not be counted */ } +TEST(disable_leak_checks) +{ + volatile void *mem; + assert(leak_check_enabled); + /* normally this should be on the beginning of the test. + * Here we need to be sure, that the leak checks are + * turned on */ + DISABLE_LEAK_CHECKS; + + mem = malloc(16); + assert(mem); +} + FAIL_TEST(sanity_malloc_indirect) { struct wl_array array; diff --git a/tests/test-runner.c b/tests/test-runner.c index 2e6ad338..70fa0ae6 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -175,6 +175,8 @@ check_leaks(int supposed_alloc, int supposed_fds) num_fds - supposed_fds); abort(); } + } else { + fprintf(stderr, "Leak checks disabled\n"); } } diff --git a/tests/test-runner.h b/tests/test-runner.h index 5963ab62..6054da56 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -62,4 +62,10 @@ test_usleep(useconds_t); void test_sleep(unsigned int); +#define DISABLE_LEAK_CHECKS \ + do { \ + extern int leak_check_enabled; \ + leak_check_enabled = 0; \ + } while (0); + #endif From f858550cf4c0df4cdec1274eb55e0a780c6dc83c Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 19 Dec 2014 14:53:07 +0100 Subject: [PATCH 0108/1152] display-test: disable leak check in tests that use pthread pthread is leaking and it makes our tests fail. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone --- tests/display-test.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index 48c4cb9b..0f862157 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -403,6 +403,8 @@ thread_read_error(void *data) static void threading_post_err(void) { + DISABLE_LEAK_CHECKS; + struct client *c = client_connect(); pthread_t thread; @@ -467,6 +469,8 @@ thread_prepare_and_read(void *data) static void threading_cancel_read(void) { + DISABLE_LEAK_CHECKS; + struct client *c = client_connect(); pthread_t th1, th2, th3; @@ -504,6 +508,8 @@ TEST(threading_cancel_read_tst) static void threading_read_eagain(void) { + DISABLE_LEAK_CHECKS; + struct client *c = client_connect(); pthread_t th1, th2, th3; @@ -560,6 +566,8 @@ thread_prepare_and_read2(void *data) static void threading_read_after_error(void) { + DISABLE_LEAK_CHECKS; + struct client *c = client_connect(); pthread_t thread; From b5fca036cc2bfc224a3db4724c00543d98008cb5 Mon Sep 17 00:00:00 2001 From: Jon Cruz Date: Wed, 28 Jan 2015 17:24:04 -0800 Subject: [PATCH 0109/1152] doc: Switch from static image files to generated diagrams. Switches diagrams from using static PNG images to instead generate them via simple graphviz DOT markup files. Signed-off-by: Jon A. Cruz --- configure.ac | 13 +++++ doc/doxygen/Makefile.am | 15 ++++- doc/doxygen/dot/wayland-architecture.gv | 39 +++++++++++++ doc/doxygen/dot/x-architecture.gv | 54 ++++++++++++++++++ doc/publican/Makefile.am | 29 ++++++---- .../sources/images/wayland-architecture.png | Bin 29162 -> 0 bytes .../sources/images/x-architecture.png | Bin 37306 -> 0 bytes 7 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 doc/doxygen/dot/wayland-architecture.gv create mode 100644 doc/doxygen/dot/x-architecture.gv delete mode 100644 doc/publican/sources/images/wayland-architecture.png delete mode 100644 doc/publican/sources/images/x-architecture.png diff --git a/configure.ac b/configure.ac index e749b006..b0a959ae 100644 --- a/configure.ac +++ b/configure.ac @@ -27,6 +27,7 @@ AM_SILENT_RULES([yes]) # Check for programs AC_PROG_CC AC_PROG_CXX +AC_PROG_GREP # check if we have C++ compiler. This is hacky workaround, # for a reason why it is this way see @@ -135,6 +136,18 @@ if test "x$enable_documentation" = "xyes"; then AC_MSG_ERROR([Documentation build requested but xmlto not found. Install xmlto or disable the documentation using --disable-documentation]) fi + AC_PATH_PROG(DOT, dot) + if test "x$DOT" = "x"; then + AC_MSG_ERROR([Documentation build requested but graphviz's dot not found. Install graphviz or disable the documentation using --disable-documentation]) + fi + AC_MSG_CHECKING([for compatible dot version]) + dot_version=`$DOT -V 2>&1|$GREP -oP '(?<=version\W)@<:@0-9.@:>@*(?=\W(.*))'` + AS_VERSION_COMPARE([$dot_version], [2.26.0], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([Graphviz dot $dot_version too old. Graphviz 2.26+ required for documentation build. Install required graphviz version or disable the documentation using --disable-documentation])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([yes])]) + AC_CONFIG_FILES([ doc/doxygen/wayland.doxygen ]) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 8c4618a8..ea206b94 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -1,4 +1,6 @@ +.SUFFIXES = .gv .png + noinst_DATA = xml/Client/index.xml xml/Server/index.xml dist_noinst_DATA = wayland.doxygen.in @@ -22,15 +24,21 @@ scanned_src_files_man = \ $(top_srcdir)/src/wayland-client.c \ $(top_srcdir)/src/wayland-client.h +diagramsdir := dot +diagramssrc := $(wildcard $(diagramsdir)/*.gv) +diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png)) + # find all man/man3/wl_foo.3 pages # for this to work, we need to create them before the man target (hence # all-local below) dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") # Listing various directories that might need to be created. -alldirs := xml/Client xml/Server man/man3 +alldirs := xml xml/Client xml/Server man/man3 -xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen | xml/% +$(diagrams): $(diagramssrc) + +xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen $(diagrams) | xml/% $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/$*"; \ @@ -45,6 +53,9 @@ man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3 echo "INPUT= $(scanned_src_files_man)"; \ ) | $(DOXYGEN) - +xml/%.png: $(diagramsdir)/%.gv | xml + $(AM_V_GEN)$(DOT) -Tpng -o$@ $< + # general rule to create one of the listed directories. $(alldirs): $(AM_V_GEN)$(MKDIR_P) $@ diff --git a/doc/doxygen/dot/wayland-architecture.gv b/doc/doxygen/dot/wayland-architecture.gv new file mode 100644 index 00000000..b86f4b5e --- /dev/null +++ b/doc/doxygen/dot/wayland-architecture.gv @@ -0,0 +1,39 @@ +digraph arch_wayland { + edge[ + fontname="DejaVu Sans"; + dir="both"; + arrowtail="dot"; + arrowsize=.5; + fontname="DejaVu Sans" + fontsize="18"; + ] + + node[ + shape="Mrecord"; + color=none; + fillcolor="#ffbc00"; + style="filled"; + fontname="DejaVu Sans" + fontsize="18"; + ] + + c1 [label="Wayland Client"; URL="#c1"] + c2 [label="Wayland Client"; URL="#c2"] + + comp [tooltip="Wayland Compositor" label="|{|Wayland\nCompositor|}|"; URL="#comp"] + + impl [tooltip="KMS evdev Kernel" label="|{{KMS|evdev}|Kernel}|"; URL="#impl"] + + + c1 -> comp [taillabel="③"; labeldistance=2.5; URL="#step_3"]; + c2 -> comp; + + comp -> c1 [label="②"; URL="#step_2"]; + comp -> c2; + + comp -> impl [xlabel = "④"; URL="#step_4"]; + comp -> impl [style = invis; label=" "]; + impl -> comp [xlabel = "①"; URL="#step_1"]; + + c1 -> c2 [style=invis]; + } diff --git a/doc/doxygen/dot/x-architecture.gv b/doc/doxygen/dot/x-architecture.gv new file mode 100644 index 00000000..85c98a3c --- /dev/null +++ b/doc/doxygen/dot/x-architecture.gv @@ -0,0 +1,54 @@ +digraph arch_x { + edge[ + fontname="DejaVu Sans"; + dir="both"; + arrowtail="dot"; + arrowsize=.5; + fontname="DejaVu Sans" + fontsize="18"; + ] + + node[ + shape="Mrecord"; + color=none; + fillcolor="#ffbc00"; + style="filled"; + fontname="DejaVu Sans" + fontsize="18"; + ] + + { + rank=same; + c1 [label="X Client"; URL="#c1"] + c3 [label="X Client"; URL="#c3"] + } + c2 [label="X Client"; URL="#c2"] + + { + rank=same; + xserver [tooltip="X Server" label="|{|X Server|}|"; URL="#xserver"] + comp [tooltip="Compositor" label="|{|Compositor|}|"; URL="#comp"] + } + + impl [tooltip="KMS evdev Kernel" label="|{{KMS|evdev}|Kernel}|"; URL="#impl"] + + c1 -> xserver [taillabel="③"; labeldistance=2; URL="#step_3"]; + c2 -> xserver; + c3 -> xserver; + + xserver -> c1 [taillabel="②"; labeldistance=2; URL="#step_2"]; + xserver -> c2; + xserver -> c3; + + xserver -> impl [taillabel = "⑥"; labeldistance=1.75; URL="#step_6"]; + xserver -> impl [style = invis; label=" "]; + impl -> xserver [taillabel = "①"; labeldistance=1.75; URL="#step_1"]; + + xserver -> comp [style=invis]; + xserver -> comp [taillabel="④"; labeldistance=1.75; labelangle=-45; URL="#step_4"]; + comp -> xserver [taillabel="⑤"; URL="#step_5"]; + comp -> xserver [style=invis] + + c1 -> c2 [style=invis]; + c3 -> c2 [style=invis]; + } diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 332399df..a4d6d581 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -12,6 +12,9 @@ # $(builddir)/en-US # * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US +doxydir := $(top_builddir)/doc/doxygen +html_destdir := $(builddir)/Wayland/en-US/html + publican_sources = \ $(srcdir)/sources/Wayland.ent \ $(srcdir)/sources/Wayland.xml \ @@ -25,9 +28,7 @@ publican_sources = \ $(srcdir)/sources/Protocol.xml \ $(srcdir)/sources/Compositors.xml \ $(srcdir)/sources/images/icon.svg \ - $(srcdir)/sources/images/wayland-architecture.png \ - $(srcdir)/sources/images/wayland.png \ - $(srcdir)/sources/images/x-architecture.png + $(srcdir)/sources/images/wayland.png css_sources = \ $(srcdir)/sources/css/brand.css \ @@ -38,9 +39,11 @@ css_sources = \ img_sources = \ $(srcdir)/sources/images/icon.svg \ - $(srcdir)/sources/images/wayland-architecture.png \ - $(srcdir)/sources/images/wayland.png \ - $(srcdir)/sources/images/x-architecture.png + $(srcdir)/sources/images/wayland.png + +doxygen_img_sources := \ + $(doxydir)/xml/wayland-architecture.png \ + $(doxydir)/xml/x-architecture.png if HAVE_XMLTO if HAVE_XSLTPROC @@ -51,18 +54,15 @@ XMLTO_PARAM = \ --stringparam toc.section.depth=1 \ --stringparam html.stylesheet=css/default.css -doxydir := $(top_builddir)/doc/doxygen - -html_destdir = $(builddir)/Wayland/en-US/html - # Listing various directories that might need to be created. alldirs := $(builddir)/en-US $(builddir)/en-US/images $(html_destdir) $(html_destdir)/css $(html_destdir)/images html_css_targets = $(addprefix $(html_destdir)/css/,$(notdir $(css_sources))) html_img_targets = $(addprefix $(html_destdir)/images/,$(notdir $(img_sources))) +doxygen_img_targets := $(doxygen_img_sources:$(doxydir)/xml/%=$(html_destdir)/images/%) -$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) | $(builddir)/en-US +$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) $(doxygen_img_targets) | $(builddir)/en-US $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html $(builddir)/en-US/Wayland.xml -o $(html_destdir) @touch $@ @@ -72,6 +72,9 @@ $(html_destdir)/css/%: $(srcdir)/sources/css/% | $(html_destdir)/css $(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images $(AM_V_GEN)cp -f $< $@ +$(html_destdir)/images/%: $(doxydir)/xml/% | $(html_destdir)/images + $(AM_V_GEN)cp -f $< $@ + pubdir = $(docdir)/Wayland/en-US publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \ @@ -104,6 +107,10 @@ $(builddir)/en-US/%: $(srcdir)/sources/% $(publican_sources) | $(builddir)/en-US $(AM_V_GEN)cp -f $< $@ $(AM_V_at)chmod a+w $@ +$(builddir)/en-US/images/%: $(doxydir)/xml/% | $(builddir)/en-US/images + $(AM_V_GEN)cp -f $< $@ + $(AM_V_at)chmod a+w $@ + # general rule to create one of the listed directories. $(alldirs): $(AM_V_GEN)$(MKDIR_P) $@ diff --git a/doc/publican/sources/images/wayland-architecture.png b/doc/publican/sources/images/wayland-architecture.png deleted file mode 100644 index 4f92e0fb93825a68095b75d499bac00e968419e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29162 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 diff --git a/doc/publican/sources/images/x-architecture.png b/doc/publican/sources/images/x-architecture.png deleted file mode 100644 index 098205b57a973311c22c914073fe53414f4c0a35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37306 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 Date: Wed, 28 Jan 2015 17:24:05 -0800 Subject: [PATCH 0110/1152] doc: Create hot-linked areas in documents. Added xslt processing to give DocBook output diagram image maps/hot-linked areas consistent with those automatically generated by Doxygen. Signed-off-by: Jon A. Cruz --- doc/doxygen/Makefile.am | 10 +++- doc/publican/Makefile.am | 21 ++++++-- doc/publican/merge-mapcoords.xsl | 64 +++++++++++++++++++++++ doc/publican/sources/Architecture.xml | 74 ++++++++++++++++----------- 4 files changed, 134 insertions(+), 35 deletions(-) create mode 100644 doc/publican/merge-mapcoords.xsl diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index ea206b94..283e0777 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -1,5 +1,5 @@ -.SUFFIXES = .gv .png +.SUFFIXES = .gv .png .map noinst_DATA = xml/Client/index.xml xml/Server/index.xml dist_noinst_DATA = wayland.doxygen.in @@ -27,6 +27,7 @@ scanned_src_files_man = \ diagramsdir := dot diagramssrc := $(wildcard $(diagramsdir)/*.gv) diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png)) +diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map)) # find all man/man3/wl_foo.3 pages # for this to work, we need to create them before the man target (hence @@ -38,7 +39,9 @@ alldirs := xml xml/Client xml/Server man/man3 $(diagrams): $(diagramssrc) -xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen $(diagrams) | xml/% +$(diagram_maps): $(diagramssrc) + +xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | xml/% $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/$*"; \ @@ -56,6 +59,9 @@ man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3 xml/%.png: $(diagramsdir)/%.gv | xml $(AM_V_GEN)$(DOT) -Tpng -o$@ $< +xml/%.map: $(diagramsdir)/%.gv | xml + $(AM_V_GEN)$(DOT) -Tcmapx_np -o$@ $< + # general rule to create one of the listed directories. $(alldirs): $(AM_V_GEN)$(MKDIR_P) $@ diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index a4d6d581..7e4fc48b 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -23,13 +23,15 @@ publican_sources = \ $(srcdir)/sources/Foreword.xml \ $(srcdir)/sources/Preface.xml \ $(srcdir)/sources/Revision_History.xml \ - $(srcdir)/sources/Introduction.xml \ - $(srcdir)/sources/Architecture.xml \ $(srcdir)/sources/Protocol.xml \ $(srcdir)/sources/Compositors.xml \ $(srcdir)/sources/images/icon.svg \ $(srcdir)/sources/images/wayland.png +processed_sources := \ + $(srcdir)/sources/Architecture.xml \ + $(srcdir)/sources/Introduction.xml + css_sources = \ $(srcdir)/sources/css/brand.css \ $(srcdir)/sources/css/common.css \ @@ -45,6 +47,10 @@ doxygen_img_sources := \ $(doxydir)/xml/wayland-architecture.png \ $(doxydir)/xml/x-architecture.png +map_sources := \ + $(doxydir)/xml/x-architecture.map \ + $(doxydir)/xml/wayland-architecture.map + if HAVE_XMLTO if HAVE_XSLTPROC noinst_DATA = $(builddir)/Wayland $(publican_targets) @@ -61,8 +67,10 @@ alldirs := $(builddir)/en-US $(builddir)/en-US/images $(html_destdir) $(html_des html_css_targets = $(addprefix $(html_destdir)/css/,$(notdir $(css_sources))) html_img_targets = $(addprefix $(html_destdir)/images/,$(notdir $(img_sources))) doxygen_img_targets := $(doxygen_img_sources:$(doxydir)/xml/%=$(html_destdir)/images/%) +map_targets := $(map_sources:$(doxydir)/xml/%=$(builddir)/en-US/images/%) +processed_targets := $(processed_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) -$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) $(doxygen_img_targets) | $(builddir)/en-US +$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) $(processed_targets) $(doxygen_img_targets) | $(builddir)/en-US $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html $(builddir)/en-US/Wayland.xml -o $(html_destdir) @touch $@ @@ -111,6 +119,13 @@ $(builddir)/en-US/images/%: $(doxydir)/xml/% | $(builddir)/en-US/images $(AM_V_GEN)cp -f $< $@ $(AM_V_at)chmod a+w $@ +# More specific rule to override explicitly listed targets and perform xslt +# modifications on them. +# Note that we can't use $< as all targets must be there +$(processed_targets): $(processed_sources) $(map_targets) $(srcdir)/merge-mapcoords.xsl | $(builddir)/en-US/images + $(AM_V_GEN)$(XSLTPROC) --stringparam basedir $(builddir)/en-US \ + $(srcdir)/merge-mapcoords.xsl $(addprefix $(srcdir)/sources/,$(notdir $@)) > $@ + # general rule to create one of the listed directories. $(alldirs): $(AM_V_GEN)$(MKDIR_P) $@ diff --git a/doc/publican/merge-mapcoords.xsl b/doc/publican/merge-mapcoords.xsl new file mode 100644 index 00000000..7adaca36 --- /dev/null +++ b/doc/publican/merge-mapcoords.xsl @@ -0,0 +1,64 @@ + + + + + + + +%BOOK_ENTITIES; +]> +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/sources/Architecture.xml b/doc/publican/sources/Architecture.xml index 5b9300f8..5d9ada0c 100644 --- a/doc/publican/sources/Architecture.xml +++ b/doc/publican/sources/Architecture.xml @@ -16,19 +16,27 @@ This is where we are now with X: - - - - - - - X architecture diagram - - - +

+ X architecture diagram + + + + + + + + + + + + + + + +
- + The kernel gets an event from an input device and sends it to X through the evdev @@ -39,7 +47,7 @@ event standard. - + The X server determines which window the event affects and sends it to the clients @@ -53,7 +61,7 @@ etc). - + The client looks at the event and decides what to do. Often the UI will have to change @@ -64,7 +72,7 @@ X server. - + When the X server receives the rendering request, it sends it to the driver to let it @@ -74,7 +82,7 @@ the compositor as a damage event. - + The damage event tells the compositor that something changed in the window and that it @@ -86,7 +94,7 @@ to go through the X server to render this. - + The X server receives the rendering requests from the compositor and either copies the @@ -125,19 +133,25 @@ to the clients and lets the client send the damage event directly to the compositor: - - - - - - - Wayland architecture diagram - - - +
+ Wayland architecture diagram + + + + + + + + + + + + + +
- + The kernel gets an event and sends it to the compositor. This @@ -146,7 +160,7 @@ input drivers in the kernel. - + The compositor looks through its scenegraph to determine which window @@ -168,7 +182,7 @@ transformation for the input events. - + As in the X case, when the client receives the event, it updates the @@ -180,7 +194,7 @@ updated. - + The compositor collects damage requests from its clients and then From 7575e2ea19dcb6012a6fd4729197d12a68b89025 Mon Sep 17 00:00:00 2001 From: Jon Cruz Date: Wed, 28 Jan 2015 17:24:06 -0800 Subject: [PATCH 0111/1152] doc: update diagrams for compatibility. Change attribute separators for compatiblity with graphviz older than 2.30. Signed-off-by: Jon A. Cruz --- doc/doxygen/dot/wayland-architecture.gv | 44 +++++++++++----------- doc/doxygen/dot/x-architecture.gv | 50 ++++++++++++------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/doc/doxygen/dot/wayland-architecture.gv b/doc/doxygen/dot/wayland-architecture.gv index b86f4b5e..2d5db841 100644 --- a/doc/doxygen/dot/wayland-architecture.gv +++ b/doc/doxygen/dot/wayland-architecture.gv @@ -1,39 +1,39 @@ digraph arch_wayland { edge[ - fontname="DejaVu Sans"; - dir="both"; - arrowtail="dot"; - arrowsize=.5; - fontname="DejaVu Sans" - fontsize="18"; + fontname="DejaVu Sans", + dir="both", + arrowtail="dot", + arrowsize=.5, + fontname="DejaVu Sans", + fontsize="18", ] node[ - shape="Mrecord"; - color=none; - fillcolor="#ffbc00"; - style="filled"; - fontname="DejaVu Sans" - fontsize="18"; + shape="Mrecord", + color=none, + fillcolor="#ffbc00", + style="filled", + fontname="DejaVu Sans", + fontsize="18", ] - c1 [label="Wayland Client"; URL="#c1"] - c2 [label="Wayland Client"; URL="#c2"] + c1 [label="Wayland Client", URL="#c1"] + c2 [label="Wayland Client", URL="#c2"] - comp [tooltip="Wayland Compositor" label="|{|Wayland\nCompositor|}|"; URL="#comp"] + comp [tooltip="Wayland Compositor", label="|{|Wayland\nCompositor|}|", URL="#comp"] - impl [tooltip="KMS evdev Kernel" label="|{{KMS|evdev}|Kernel}|"; URL="#impl"] + impl [tooltip="KMS evdev Kernel", label="|{{KMS|evdev}|Kernel}|", URL="#impl"] - c1 -> comp [taillabel="③"; labeldistance=2.5; URL="#step_3"]; + c1 -> comp [taillabel="③", labeldistance=2.5, URL="#step_3"]; c2 -> comp; - comp -> c1 [label="②"; URL="#step_2"]; + comp -> c1 [label="②", URL="#step_2"]; comp -> c2; - comp -> impl [xlabel = "④"; URL="#step_4"]; - comp -> impl [style = invis; label=" "]; - impl -> comp [xlabel = "①"; URL="#step_1"]; + comp -> impl [xlabel = "④", URL="#step_4"]; + comp -> impl [style = invis, label=" "]; + impl -> comp [xlabel = "①", URL="#step_1"]; c1 -> c2 [style=invis]; - } +} diff --git a/doc/doxygen/dot/x-architecture.gv b/doc/doxygen/dot/x-architecture.gv index 85c98a3c..4ea49bfa 100644 --- a/doc/doxygen/dot/x-architecture.gv +++ b/doc/doxygen/dot/x-architecture.gv @@ -1,52 +1,52 @@ digraph arch_x { edge[ - fontname="DejaVu Sans"; - dir="both"; - arrowtail="dot"; - arrowsize=.5; - fontname="DejaVu Sans" - fontsize="18"; + fontname="DejaVu Sans", + dir="both", + arrowtail="dot", + arrowsize=.5, + fontname="DejaVu Sans", + fontsize="18", ] node[ - shape="Mrecord"; - color=none; - fillcolor="#ffbc00"; - style="filled"; - fontname="DejaVu Sans" - fontsize="18"; + shape="Mrecord", + color=none, + fillcolor="#ffbc00", + style="filled", + fontname="DejaVu Sans", + fontsize="18", ] { rank=same; - c1 [label="X Client"; URL="#c1"] - c3 [label="X Client"; URL="#c3"] + c1 [label="X Client", URL="#c1"] + c3 [label="X Client", URL="#c3"] } - c2 [label="X Client"; URL="#c2"] + c2 [label="X Client", URL="#c2"] { rank=same; - xserver [tooltip="X Server" label="|{|X Server|}|"; URL="#xserver"] - comp [tooltip="Compositor" label="|{|Compositor|}|"; URL="#comp"] + xserver [tooltip="X Server", label="|{|X Server|}|", URL="#xserver"] + comp [tooltip="Compositor", label="|{|Compositor|}|", URL="#comp"] } - impl [tooltip="KMS evdev Kernel" label="|{{KMS|evdev}|Kernel}|"; URL="#impl"] + impl [tooltip="KMS evdev Kernel", label="|{{KMS|evdev}|Kernel}|", URL="#impl"] - c1 -> xserver [taillabel="③"; labeldistance=2; URL="#step_3"]; + c1 -> xserver [taillabel="③", labeldistance=2, URL="#step_3"]; c2 -> xserver; c3 -> xserver; - xserver -> c1 [taillabel="②"; labeldistance=2; URL="#step_2"]; + xserver -> c1 [taillabel="②", labeldistance=2, URL="#step_2"]; xserver -> c2; xserver -> c3; - xserver -> impl [taillabel = "⑥"; labeldistance=1.75; URL="#step_6"]; - xserver -> impl [style = invis; label=" "]; - impl -> xserver [taillabel = "①"; labeldistance=1.75; URL="#step_1"]; + xserver -> impl [taillabel="⑥", labeldistance=1.75, URL="#step_6"]; + xserver -> impl [style=invis, label=" "]; + impl -> xserver [taillabel="①", labeldistance=1.75, URL="#step_1"]; xserver -> comp [style=invis]; - xserver -> comp [taillabel="④"; labeldistance=1.75; labelangle=-45; URL="#step_4"]; - comp -> xserver [taillabel="⑤"; URL="#step_5"]; + xserver -> comp [taillabel="④", labeldistance=1.75, labelangle=-45, URL="#step_4"]; + comp -> xserver [taillabel="⑤", URL="#step_5"]; comp -> xserver [style=invis] c1 -> c2 [style=invis]; From 5ec8062df26f21cfe7a031eaf83a1b4d99085f36 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 28 Jan 2015 09:25:03 -0600 Subject: [PATCH 0112/1152] event-loop: Dispatch idle callbacks twice To fix a shutdown crash in weston's x11 compositor I want to move the weston X window close to an idle handler. Since idle handlers are processed at the start of an event loop, the handler that deals with window close will run at the start of the next input_loop dispatch, after which the dispatcher blocks on epoll forever (since all input events that will ever occur have been consumed). Dispatching idle callbacks both at the start and end of event-loop processing will prevent this permanent blocking. Note that just moving the callback dispatch could theoretically result in an idle callback being delayed indefinitely while waiting for epoll_wait() to complete. Callbacks are removed from the list when they're run, so the second dispatch won't result in any extra calls. Signed-off-by: Derek Foreman Reviewed-by: Giulio Camuffo Reviewed-by: Bryce Harrington --- src/event-loop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index 1f571ba4..d257d78c 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -421,10 +421,12 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) wl_event_loop_process_destroy_list(loop); + wl_event_loop_dispatch_idle(loop); + do { n = post_dispatch_check(loop); } while (n > 0); - + return 0; } From cd0cf5a106b0578da9706f9eb3ceac3ff07c26ee Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Tue, 6 Jan 2015 17:35:56 +0100 Subject: [PATCH 0113/1152] doc/publican/Makefile.am: Add a missing order-only prerequisite Otherwise a parallel make invocation could fail due to the directory not existing. Signed-off-by: Rui Matos Reviewed-by: Jon A. Cruz --- doc/publican/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 7e4fc48b..4a7f2259 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -96,7 +96,7 @@ $(builddir)/en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir) $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-to-docbook.xsl \ $(top_srcdir)/protocol/wayland.xml > $@ -$(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl +$(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl | $(builddir)/en-US $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-interfaces-to-docbook.xsl \ $(top_srcdir)/protocol/wayland.xml > $@ From a4afd90f9f0c27ed5f3f313b915c260673f8be34 Mon Sep 17 00:00:00 2001 From: Andrew Oakley Date: Tue, 27 Jan 2015 17:18:13 +0000 Subject: [PATCH 0114/1152] configure.ac: use pkg-config to find expat This is now done in the same way as the libffi dependency and still allows the library to be installed in a non-standard location (with PKG_CONFIG_PATH). --- Makefile.am | 1 + configure.ac | 11 +---------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Makefile.am b/Makefile.am index 43b741a8..0fccf863 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,6 +65,7 @@ if ENABLE_SCANNER wayland_scanner = $(top_builddir)/wayland-scanner bin_PROGRAMS = wayland-scanner wayland_scanner_SOURCES = src/scanner.c +wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS) wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la $(BUILT_SOURCES) : wayland-scanner pkgconfig_DATA += src/wayland-scanner.pc diff --git a/configure.ac b/configure.ac index b0a959ae..6c3d611f 100644 --- a/configure.ac +++ b/configure.ac @@ -84,17 +84,8 @@ AC_ARG_WITH(icondir, [ --with-icondir= Look for cursor icons here], [ ICONDIR=${datadir}/icons]) AC_SUBST([ICONDIR]) -EXPAT_LIB="" -AC_ARG_WITH(expat, [ --with-expat= Use expat from here], - [ expat=$withval - CPPFLAGS="$CPPFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib" ] ) if test "x$enable_scanner" = "xyes"; then - AC_CHECK_HEADERS(expat.h, [AC_DEFINE(HAVE_EXPAT_H)], - [AC_MSG_ERROR([Can't find expat.h. Please install expat.])]) - AC_CHECK_LIB(expat, XML_ParserCreate, [EXPAT_LIBS="-lexpat"], - [AC_MSG_ERROR([Can't find expat library. Please install expat.])]) - AC_SUBST(EXPAT_LIBS) + PKG_CHECK_MODULES(EXPAT, [expat]) fi AC_PATH_PROG(XSLTPROC, xsltproc) From 6be2d9aaef6b59c475d27592d97cfad3d5dd777c Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Wed, 28 Jan 2015 18:44:08 -0800 Subject: [PATCH 0115/1152] doc: Intro text for doxygen output in it's own file (This patch has been modified to apply atop current master) This makes it considerably easier to edit the text and make it different for each library. To address previous concerns with this patch, I wrote some more complete introductory text. This is based on my understanding of these libraries, which may not be correct, and is pretty rudimentary for libwayland-server! However this intro text demonstrates how to create links to the doxygen-generated text. It looks like you cannot link to methods easily as the link name contains a hash number, but links to objects and classes work. Reviewed-by: Jon A. Cruz Tested-by: Jon A. Cruz --- doc/publican/Makefile.am | 4 +- doc/publican/doxygen-to-publican.xsl | 49 +++------------ doc/publican/sources/Client.xml | 92 ++++++++++++++++++++++++++++ doc/publican/sources/Server.xml | 49 +++++++++++++++ doc/publican/sources/Wayland.xml | 5 +- 5 files changed, 154 insertions(+), 45 deletions(-) create mode 100644 doc/publican/sources/Client.xml create mode 100644 doc/publican/sources/Server.xml diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 4a7f2259..c16a7168 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -26,7 +26,9 @@ publican_sources = \ $(srcdir)/sources/Protocol.xml \ $(srcdir)/sources/Compositors.xml \ $(srcdir)/sources/images/icon.svg \ - $(srcdir)/sources/images/wayland.png + $(srcdir)/sources/images/wayland.png \ + $(srcdir)/sources/Client.xml \ + $(srcdir)/sources/Server.xml processed_sources := \ $(srcdir)/sources/Architecture.xml \ diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index cbcb2817..7c3b5075 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -4,49 +4,16 @@ - - -%BOOK_ENTITIES; -]> -]]> + - - sect-Library- - <xsl:value-of select="$which"/> API +
+ Functions + + + + +
- - The open-source reference implementation of Wayland protocol is - split in two C libraries, libwayland-client and libwayland-server. Their - main responsibility is to handle the Inter-process communication - (IPC) with each other, therefore - guaranteeing the protocol objects marshaling and messages - synchronization. - - - - Following is the Wayland library classes for the - libwayland-. This appendix describes in detail - the library's methods and their helpers, aiming implementors who - are building a Wayland . - - - - -
- Functions - - - - -
- -
diff --git a/doc/publican/sources/Client.xml b/doc/publican/sources/Client.xml new file mode 100644 index 00000000..a1e33419 --- /dev/null +++ b/doc/publican/sources/Client.xml @@ -0,0 +1,92 @@ + + + +%BOOK_ENTITIES; +]> + + Client API +
Introduction + + The open-source reference implementation of Wayland protocol is + split in two C libraries, libwayland-client and libwayland-server. Their main + responsibility is to handle the Inter-process communication + (IPC) with each other, therefore guaranteeing + the protocol objects marshaling and messages synchronization. + + + A client uses libwayland-client to communicate with one or more + wayland servers. A wl_display object is + created and manages each open connection to a server. At least one + wl_event_queue + object is created for each wl_display, this holds events as they + are recieved from the server until they can be + processed. Multi-threading is supported by creating an additional + wl_event_queue for each additional thread, each object can have + it's events placed in a particular queue, so potentially a + different thread could be made to handle the events for each + object created. + + + Though some conveinence functions are provided, libwayland-client + is designed to allow the calling code to wait for events, so that + different polling mechanisms can be used. A file descriptor is + provided, when it becomes ready for reading the calling code can + ask libwayland-client to read the available events from it into + the wl_event_queue objects. + + + The library only provides low-level access to the wayland objects. + Each object created by the client is represented by a wl_proxy object that this + library creates. This includes the id that is actually + communicated over the socket to the server, a void* data pointer + that is intended to point at a client's representation of the + object, and a pointer to a static wl_interface object, + which is generated from the xml and identifies the object's class + and can be used for introspection into the messages and events. + + + Messages are sent by calling wl_proxy_marshal. This will write a + message to the socket, by using the message id and the + wl_interface to identify the types of each argument and convert + them into stream format. Most software will call type-safe + wrappers generated from the xml description of the Wayland protocols. For + instance the C header file generated from the xml defines the + following inline function to transmit the wl_surface::attach + message: + + static inline void +wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, WL_SURFACE_ATTACH, buffer, x, y); +} + + Events (messages from the server) are handled by calling a + "dispatcher" callback the client stores in the wl_proxy for each + event. A language binding for a string-based interpreter, such as + CPython, might have a dispatcher that uses the event name from the + wl_interface to identify the function to call. The default + dispatcher uses the message id number to index an array of + functions pointers, called a wl_listener, and the wl_interface to + convert data from the stream into arguments to the function. The + C header file generated from the xml defines a per-class structure + that forces the function pointers to be of the correct type, for + instance the wl_surface::enter + event defines this pointer in the wl_surface_listener object: + + struct wl_surface_listener { + void (*enter)(void *data, struct wl_surface *, struct wl_output *); + ... +} + + +
+ &doxygen; +
diff --git a/doc/publican/sources/Server.xml b/doc/publican/sources/Server.xml new file mode 100644 index 00000000..f627d64b --- /dev/null +++ b/doc/publican/sources/Server.xml @@ -0,0 +1,49 @@ + + + +%BOOK_ENTITIES; +]> + + Server API +
Introduction + + The open-source reference implementation of Wayland protocol is + split in two C libraries, libwayland-client and + libwayland-server. Their main responsibility is to handle the + Inter-process communication (IPC) with each + other, therefore guaranteeing the protocol objects marshaling and + messages synchronization. + + + The server library is designed to work much like libwayland-client, + although it is considerably complicated due to the server needing + to support multiple versions of the protocol. It is best to learn + libwayland-client first. + + + Each open socket to a client is represented by a wl_client. The equvalent + of the wl_proxy that + libwayland-client uses to represent an object is wl_resource for + client-created objects, and wl_global for objects + created by the server. + + + Often a server is also a client for another Wayland server, and + thus must link with both libwayland-client and libwayland-server. + This produces some type name conflicts (such as the client wl_display and + server wl_display, + but the duplicate-but-not-the-same types are opaque, and accessed + only inside the correct library where it came from. Naturally that + means that the program writer needs to always know if a pointer to + a wl_display is for the server or client side and use the + corresponding functions. + +
+ &doxygen; +
diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/sources/Wayland.xml index 5ae90bb2..2f47f132 100644 --- a/doc/publican/sources/Wayland.xml +++ b/doc/publican/sources/Wayland.xml @@ -12,7 +12,6 @@ - - + + - From ccb17a05a3114414cebed49ce4af7725d705e205 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Thu, 29 Jan 2015 17:25:16 -0800 Subject: [PATCH 0116/1152] gitignore: Add the new cpp-compile-test --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4e0f5d92..defe6251 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ Makefile.in array-test client-test connection-test +cpp-compile-test display-test event-loop-test exec-fd-leak-checker From 768724495e2d15af0b9ea8303fe776201e6d49de Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 30 Jan 2015 14:57:53 -0800 Subject: [PATCH 0117/1152] configure.ac: bump version to 1.6.92 for rc1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6c3d611f..97222f08 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [6]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 23a57b69ffaad990172958ff1f64a687b8374a2d Mon Sep 17 00:00:00 2001 From: Jon Cruz Date: Fri, 30 Jan 2015 18:07:24 -0800 Subject: [PATCH 0118/1152] doc: Fix out-of-tree build and also distcheck Corrects an issue that would cause out-of-tree builds to fail and also a few items that would cause distcheck to fail. Signed-off-by: Jon A. Cruz Reviewed-by: Bryce Harrington --- doc/doxygen/Makefile.am | 4 +++- doc/publican/Makefile.am | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 283e0777..edf36526 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -24,7 +24,7 @@ scanned_src_files_man = \ $(top_srcdir)/src/wayland-client.c \ $(top_srcdir)/src/wayland-client.h -diagramsdir := dot +diagramsdir := $(srcdir)/dot diagramssrc := $(wildcard $(diagramsdir)/*.gv) diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png)) diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map)) @@ -72,3 +72,5 @@ all-local: man/man3/wl_display.3 clean-local: rm -rf xml/ rm -rf man/ + +EXTRA_DIST = $(diagramssrc) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index c16a7168..57728a00 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -158,4 +158,9 @@ uninstall-local: endif endif -EXTRA_DIST = $(publican_sources) $(css_sources) $(img_sources) protocol-to-docbook.xsl protocol-interfaces-to-docbook.xsl doxygen-to-publican.xsl +EXTRA_DIST = \ + $(publican_sources) $(processed_sources) $(css_sources) $(img_sources) \ + protocol-to-docbook.xsl \ + protocol-interfaces-to-docbook.xsl \ + doxygen-to-publican.xsl \ + merge-mapcoords.xsl From 48bf640d16b9f3a6920220e216d55665b42dc0c6 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 30 Jan 2015 19:04:07 -0800 Subject: [PATCH 0119/1152] configure.ac: re-bump version to 1.6.92 for rc1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 97222f08..0426b532 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [6]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 8094426a4168b78b924210e97ef178c78c1d296f Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Mon, 2 Feb 2015 10:40:21 +0100 Subject: [PATCH 0120/1152] test-runner: wait for concrete pid After running a test in fork, we were waiting for any child to terminate. It is OK unless the child forks again. If the child calls fork, the waitid can catch the child's child termination, stop block and run another test while the former test is still running. This is racy i. e. when adding socket. Since we have test compositor which uses fork, this situation can occur pretty frequently. Signed-off-by: Marek Chalupa Reviewed-by: Jon A. Cruz Reviewed-by: Daniel Stone --- tests/test-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 70fa0ae6..0412e858 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -351,7 +351,7 @@ int main(int argc, char *argv[]) if (pid == 0) run_test(t); /* never returns */ - if (waitid(P_ALL, 0, &info, WEXITED)) { + if (waitid(P_PID, pid, &info, WEXITED)) { stderr_set_color(RED); fprintf(stderr, "waitid failed: %m\n"); stderr_reset_color(); From 310fea467cf714d3ed7d66747c463790246f9be1 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 27 Jan 2015 16:32:16 -0800 Subject: [PATCH 0121/1152] doc: Fill in high level description for Surfaces Signed-off-by: Bryce Harrington Reviewed-by: Jon A. Cruz --- doc/publican/sources/Protocol.xml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 5f3e8526..477063be 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -282,9 +282,16 @@
Surfaces - Surfaces are created by the client. - Clients don't know the global position of their surfaces, and - cannot access other clients surfaces. + A surface manages a rectangular grid of pixels that clients create + for displaying their content to the screen. Clients don't know + the global position of their surfaces, and cannot access other + clients' surfaces. + + + Once the client has finished writing pixels, it 'commits' the + buffer; this permits the compositor to access the buffer and read + the pixels. When the compositor is finished, it releases the + buffer back to the client. See for the protocol From 76fe89ed535be7ff20e39d5d2ec3b26cb3fae37e Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 7 Jan 2015 11:56:54 -0800 Subject: [PATCH 0122/1152] tests: Fix FAIL in sanity-test (*timeout*) when Yama LSM enabled This fixes a regression in the testsuite since c3653f7f, where four of the timeout tests fail with "Timeouts suppressed" messages. The timeouts are being suppressed because the testsuite is erroneously detecting that a debugger is attached. This detection mechanism (adopted from libinput) uses ptrace to test if there is a debugger parent process that can be attached. Unfortunately, this is an unreliable test: Kernel security policies exist to restrict the scope of ptrace to prevent processes from snooping on one another.[1] This security policy is set as the default on Ubuntu, and potentially other Linux distributions.[2] The Yama documentation suggests, "For software that has defined application-specific relationships between a debugging process and its inferior (crash handlers, etc), prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which other process (and its descendents) are allowed to call PTRACE_ATTACH against it." This prctl call has no effect if Yama LSM is not loaded. The child needs to be synchronized to the client to prevent a race condition where the child might try to operate before the parent has finished its prctl call. This synchronization is done via pipes. This patch can be tested by running sanity-test with /proc/sys/kernel/yama/ptrace_scope set to 0 or 1; the test must pass for either value. 1: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=2d514487faf188938a4ee4fb3464eeecfbdcf8eb 2: https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#ptrace_Protection Signed-off-by: Bryce Harrington Reviewed-by: Marek Chalupa Reviewed-by: Daniel Stone Reviewed-by: Derek Foreman v4: Allow parent to communicate error state to child to prevent leaving child in zombie state if parent hits an error. v5: Check errno instead of rc for error. Don't waitpid on ppid. Signed-off-by: Bryce Harrington --- tests/test-runner.c | 64 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 0412e858..1e5f5878 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -34,6 +34,10 @@ #include #include #include +#include +#ifndef PR_SET_PTRACER +# define PR_SET_PTRACER 0x59616d61 +#endif #include "test-runner.h" @@ -267,29 +271,65 @@ stderr_reset_color(void) /* this function is taken from libinput/test/litest.c * (rev 028513a0a723e97941c39) + * + * Returns: 1 if a debugger is confirmed present; 0 if no debugger is + * present or if it can't be determined. */ static int is_debugger_attached(void) { int status; int rc; - pid_t pid = fork(); + pid_t pid; + int pipefd[2]; - if (pid == -1) + if (pipe(pipefd) == -1) { + perror("pipe"); return 0; + } - if (pid == 0) { + pid = fork(); + if (pid == -1) { + perror("fork"); + close(pipefd[0]); + close(pipefd[1]); + return 0; + } else if (pid == 0) { + char buf; pid_t ppid = getppid(); - if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0) { - waitpid(ppid, NULL, 0); - ptrace(PTRACE_CONT, NULL, NULL); - ptrace(PTRACE_DETACH, ppid, NULL, NULL); - rc = 0; - } else { - rc = 1; - } - _exit(rc); + + /* Wait until parent is ready */ + close(pipefd[1]); /* Close unused write end */ + read(pipefd[0], &buf, 1); + close(pipefd[0]); + if (buf == '-') + _exit(1); + if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) != 0) + _exit(1); + if (!waitpid(-1, NULL, 0)) + _exit(1); + ptrace(PTRACE_CONT, NULL, NULL); + ptrace(PTRACE_DETACH, ppid, NULL, NULL); + _exit(0); } else { + close(pipefd[0]); + + /* Enable child to ptrace the parent process */ + rc = prctl(PR_SET_PTRACER, pid); + if (rc != 0 && errno != EINVAL) { + /* An error prevents us from telling if a debugger is attached. + * Instead of propagating the error, assume no debugger present. + * But note the error to the log as a clue for troubleshooting. + * Then flag the error state to the client by sending '-'. + */ + perror("prctl"); + write(pipefd[1], "-", 1); + } else { + /* Signal to client that parent is ready by passing '+' */ + write(pipefd[1], "+", 1); + } + close(pipefd[1]); + waitpid(pid, &status, 0); rc = WEXITSTATUS(status); } From 371a9e0aefcc2bdef9c044a59d613ce6c175ed73 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Tue, 3 Feb 2015 14:26:58 -0800 Subject: [PATCH 0123/1152] configure.ac: Fallback to older detection code if pkg-config can't find expat This paritally reverts commit a4afd90f9f0c27ed5f3f313b915c260673f8be34. On older expat versions (ie the one on Ubuntu 12.04) there is no pkg-config file, so fall back to a test for the header and library. In addition the source for expat does not seem to be in a git repository but in cvs instead and it seems preferrable to not require cvs to build wayland. The restored test has been updated to use AC_SEARCH_LIBS. This version uses empty square brackets for the unused branches, similar to many other if statements in configure.ac. Reviewed-by: Bryce Harrington Reviewed-by: Andrew Oakley --- configure.ac | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0426b532..5a8e915f 100644 --- a/configure.ac +++ b/configure.ac @@ -85,7 +85,16 @@ AC_ARG_WITH(icondir, [ --with-icondir= Look for cursor icons here], AC_SUBST([ICONDIR]) if test "x$enable_scanner" = "xyes"; then - PKG_CHECK_MODULES(EXPAT, [expat]) + PKG_CHECK_MODULES(EXPAT, [expat], [], + [AC_CHECK_HEADERS(expat.h, [], + [AC_MSG_ERROR([Can't find expat.h. Please install expat.])]) + SAVE_LIBS="$LIBS" + AC_SEARCH_LIBS(XML_ParserCreate, expat, [], + [AC_MSG_ERROR([Can't find expat library. Please install expat.])]) + EXPAT_LIBS="$LIBS" + LIBS="$SAVE_LIBS" + AC_SUBST(EXPAT_LIBS) + ]) fi AC_PATH_PROG(XSLTPROC, xsltproc) From 52d971c924d0147d6949096c9cf001d75828a054 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 6 Feb 2015 17:56:44 -0800 Subject: [PATCH 0124/1152] configure.ac: bump to version 1.6.93 for rc2 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5a8e915f..7ef77ebd 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [6]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 8e9d5a108476b3435a8286613b9a63b69afd92b7 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 13 Feb 2015 19:17:56 -0800 Subject: [PATCH 0125/1152] configure.ac: bump to version 1.7.0 for release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7ef77ebd..b2e14186 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [6]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [7]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From f3a5ca999e7efabc873bd2ee1d5fbe07e1e73ddd Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 17 Feb 2015 18:34:33 -0800 Subject: [PATCH 0126/1152] configure.ac: bump version to 1.7.90 Master is open for new features again Signed-off-by: Bryce Harrington --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b2e14186..6bbec59b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [7]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 99d2775ae95784a3e9f4bcd6d2ef48cf36ca8c15 Mon Sep 17 00:00:00 2001 From: Hardening Date: Wed, 25 Feb 2015 15:03:33 +0100 Subject: [PATCH 0127/1152] wayland.xml: fixed a typo --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 2a498054..4fb80350 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1389,7 +1389,7 @@ - + From 8b2fbf872280a68f82ab6aae68a89fd58cc9996b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 3 Mar 2015 15:40:58 +0800 Subject: [PATCH 0128/1152] protocol: Change wording of subsurface placement scheduling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change wording to be more consistent with other parts of the subsurface protocol. Before this change, wl_subsurface.set_position explicitly stated that the new state was to be applied on the parents wl_surface.commit and wl_subsurface.place_above/below only said "on the next commit of the parent surface". What "committed" means is ambiguous considering that a wl_surface.commit actually defers the actual commit when in synchronized mode, but the intention has always been that placement of a subsurface should be considered part of its content, i.e. placement state should be applied when other state (buffer, regions). This patch makes that more clear. Note that prior to this patch, one could correctly have interpreted the protocol meaning that placements operations takes effect explicitly on wl_surface.commit of the parent surface no matter whether other state of the parent surface is applied at that point. This patch clarifies that that is not the case. https://bugs.freedesktop.org/show_bug.cgi?id=88857 Signed-off-by: Jonas Ådahl Acked-by: Jasper St. Pierre Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 4fb80350..88bbbc04 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2061,8 +2061,10 @@ coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. - The next wl_surface.commit on the parent surface will reset - the sub-surface's position to the scheduled coordinates. + The scheduled coordinates will take effect whenever the state of the + parent surface is applied. When this happens depends on whether the + parent surface is in synchronized mode or not. See + wl_subsurface.set_sync and wl_subsurface.set_desync for details. If more than one set_position request is invoked by the client before the commit of the parent surface, the position of a new request always @@ -2084,9 +2086,11 @@ will cause a protocol error. The z-order is double-buffered. Requests are handled in order and - applied immediately to a pending state, then committed to the active - state on the next commit of the parent surface. - See wl_surface.commit and wl_subcompositor.get_subsurface. + applied immediately to a pending state. The final pending state is + copied to the active state the next time the state of the parent + surface is applied. When this happens depends on whether the parent + surface is in synchronized mode or not. See wl_subsurface.set_sync and + wl_subsurface.set_desync for details. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. From 4908bf0d0f49c766a814eefb31534561da9e8d6e Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 4 Mar 2015 14:30:41 -0600 Subject: [PATCH 0129/1152] cursor: add wl_cursor_frame_and_duration It's useful to know how long the current cursor frame should be displayed so we can wait that long to change it. Signed-off-by: Derek Foreman Reviewed-by: Pekka Paalanen --- cursor/wayland-cursor.c | 69 ++++++++++++++++++++++++++++++++--------- cursor/wayland-cursor.h | 4 +++ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index dba3b510..1a5393ae 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -458,9 +458,61 @@ wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, } /** Find the frame for a given elapsed time in a cursor animation + * as well as the time left until next cursor change. * * \param cursor The cursor - * \param time Elapsed time since the beginning of the animation + * \param time Elapsed time in ms since the beginning of the animation + * \param duration pointer to uint32_t to store time left for this image or + * zero if the cursor won't change. + * + * \return The index of the image that should be displayed for the + * given time in the cursor animation. + */ +WL_EXPORT int +wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, + uint32_t *duration) +{ + struct cursor *cursor = (struct cursor *) _cursor; + uint32_t t; + int i; + + if (cursor->cursor.image_count == 1) { + if (duration) + *duration = 0; + return 0; + } + + i = 0; + t = time % cursor->total_delay; + + /* If there is a 0 delay in the image set then this + * loop breaks on it and we display that cursor until + * time % cursor->total_delay wraps again. + * Since a 0 delay is silly, and we've never actually + * seen one in a cursor file, we haven't bothered to + * "fix" this. + */ + while (t - cursor->cursor.images[i]->delay < t) + t -= cursor->cursor.images[i++]->delay; + + if (!duration) + return i; + + /* Make sure we don't accidentally tell the caller this is + * a static cursor image. + */ + if (t >= cursor->cursor.images[i]->delay) + *duration = 1; + else + *duration = cursor->cursor.images[i]->delay - t; + + return i; +} + +/** Find the frame for a given elapsed time in a cursor animation + * + * \param cursor The cursor + * \param time Elapsed time in ms since the beginning of the animation * * \return The index of the image that should be displayed for the * given time in the cursor animation. @@ -468,18 +520,5 @@ wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, WL_EXPORT int wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) { - struct cursor *cursor = (struct cursor *) _cursor; - uint32_t t; - int i; - - if (cursor->cursor.image_count == 1) - return 0; - - i = 0; - t = time % cursor->total_delay; - - while (t - cursor->cursor.images[i]->delay < t) - t -= cursor->cursor.images[i++]->delay; - - return i; + return wl_cursor_frame_and_duration(_cursor, time, NULL); } diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h index c7548ae7..c3884a04 100644 --- a/cursor/wayland-cursor.h +++ b/cursor/wayland-cursor.h @@ -63,6 +63,10 @@ wl_cursor_image_get_buffer(struct wl_cursor_image *image); int wl_cursor_frame(struct wl_cursor *cursor, uint32_t time); +int +wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time, + uint32_t *duration); + #ifdef __cplusplus } #endif From be47969a38d66e125b7f13b9a9b44e447219a00a Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 17 Mar 2015 15:09:30 -0700 Subject: [PATCH 0130/1152] client: Fix typo Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 0f1405c0..9adde385 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -955,7 +955,7 @@ static const struct wl_callback_listener sync_listener = { * \param queue The queue on which to run the roundtrip * \return The number of dispatched events on success or -1 on failure * - * Blocks until the server process all currently issued requests and + * Blocks until the server processes all currently issued requests and * sends out pending events on the event queue. * * \note This function uses wl_display_dispatch_queue() internally. If you From c770b8465851862b293b91d9d115a2cccadb807c Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 18 Mar 2015 01:53:22 +0100 Subject: [PATCH 0131/1152] cursor: free the array from which images are linked --- cursor/wayland-cursor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 1a5393ae..410a0d40 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -190,6 +190,7 @@ wl_cursor_destroy(struct wl_cursor *cursor) for (i = 0; i < cursor->image_count; i++) wl_cursor_image_destroy(cursor->images[i]); + free(cursor->images); free(cursor->name); free(cursor); } From e16ee74e475b5a179151b88a0a55a511fd368d74 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 19 Mar 2015 03:42:27 -0400 Subject: [PATCH 0132/1152] server: give more precise error message There are two same error messages with different cause. Let user know what is the cause of the error. Signed-off-by: Marek Chalupa Reviewed-by: Daniel Stone Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 05586340..ecbae683 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -238,7 +238,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) const struct wl_message *message; uint32_t p[2]; uint32_t resource_flags; - int opcode, size; + int opcode, size, since; int len; if (mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP)) { @@ -294,13 +294,14 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) } message = &object->interface->methods[opcode]; + since = wl_message_get_since(message); if (!(resource_flags & WL_MAP_ENTRY_LEGACY) && - resource->version > 0 && - resource->version < wl_message_get_since(message)) { + resource->version > 0 && resource->version < since) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, - "invalid method %d, object %s@%u", - opcode, + "invalid method %d (since %d < %d)" + ", object %s@%u", + opcode, resource->version, since, object->interface->name, object->id); break; From 439b0a38630eb3c1a088c84cc76019ad001bb99b Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 18 Mar 2015 18:32:54 -0700 Subject: [PATCH 0133/1152] Spelling fixes (cosmetic) A few typos in comments and protocol docs, no code changes. ./src/wayland-util.h:281: recieved ==> received ./src/wayland-client.c:115: occured ==> occurred ./src/wayland-client.c:156: occured ==> occurred ./tests/test-compositor.c:76: parallely ==> parallelly ./tests/test-compositor.c:474: recieve ==> receive ./protocol/wayland.xml:1767: layed ==> laid ./protocol/wayland.xml:2112: dependant ==> dependent ./doc/publican/sources/Client.xml:25: recieved ==> received Signed-off-by: Bryce Harrington Reviewed-by: Bill Spitzak --- doc/publican/sources/Client.xml | 2 +- protocol/wayland.xml | 4 ++-- src/wayland-client.c | 4 ++-- src/wayland-util.h | 2 +- tests/test-compositor.c | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/publican/sources/Client.xml b/doc/publican/sources/Client.xml index a1e33419..fcdd2f2f 100644 --- a/doc/publican/sources/Client.xml +++ b/doc/publican/sources/Client.xml @@ -22,7 +22,7 @@ created and manages each open connection to a server. At least one wl_event_queue object is created for each wl_display, this holds events as they - are recieved from the server until they can be + are received from the server until they can be processed. Multi-threading is supported by creating an additional wl_event_queue for each additional thread, each object can have it's events placed in a particular queue, so potentially a diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 88bbbc04..041e5f09 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1764,7 +1764,7 @@ This enumeration describes how the physical - pixels on an output are layed out. + pixels on an output are laid out. @@ -2113,7 +2113,7 @@ Change the commit behaviour of the sub-surface to synchronized - mode, also described as the parent dependant mode. + mode, also described as the parent dependent mode. In synchronized mode, wl_surface.commit on a sub-surface will accumulate the committed state in a cache, but the state will diff --git a/src/wayland-client.c b/src/wayland-client.c index 9adde385..ed108e1f 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -112,7 +112,7 @@ static int debug_client = 0; /** * This helper function wakes up all threads that are * waiting for display->reader_cond (i. e. when reading is done, - * canceled, or an error occured) + * canceled, or an error occurred) * * NOTE: must be called with display->mutex locked */ @@ -153,7 +153,7 @@ display_fatal_error(struct wl_display *display, int error) /** * This function is called for error events - * and indicates that in some object an error occured. + * and indicates that in some object an error occurred. * Difference between this function and display_fatal_error() * is that this one handles errors that will come by wire, * whereas display_fatal_error() is called for local errors. diff --git a/src/wayland-util.h b/src/wayland-util.h index a4b22b54..2bc3ff5a 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -278,7 +278,7 @@ union wl_argument { * object on which the callback is being invoked (either wl_proxy or * wl_resource). The third and fourth arguments are the opcode the wl_messsage * structure corresponding to the callback being emitted. The final argument - * is an array of arguments recieved from the other process via the wire + * is an array of arguments received from the other process via the wire * protocol. */ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, diff --git a/tests/test-compositor.c b/tests/test-compositor.c index da2a55fd..89c41407 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -73,7 +73,7 @@ enum { DISPLAY_RESUMED = 0 }; -/* Since tests can run parallely, we need unique socket names +/* Since tests can run parallelly, we need unique socket names * for each test, otherwise the test can fail on wl_display_add_socket. */ static const char * get_socket_name(void) @@ -471,7 +471,7 @@ client_disconnect(struct client *c) } /* num is number of clients that requests to stop display. - * Display is stopped after it recieve num STOP_DISPLAY requests */ + * Display is stopped after it receive num STOP_DISPLAY requests */ int stop_display(struct client *c, int num) { From 2d46da10d84eb16b810e6b181e084ceff1818f38 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 2 Mar 2015 16:08:00 +0200 Subject: [PATCH 0134/1152] Add support for direct file reading and writing in wayland-scanner. Add support for direct file reading and writing in wayland-scanner. Signed-off-by: Jussi Pakkanen Reviewed-by: Pekka Paalanen Acked-by: David Fort --- src/scanner.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 1f1e59a7..efdc69c6 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -39,11 +39,12 @@ enum side { static int usage(int ret) { - fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n"); + fprintf(stderr, "usage: ./scanner [client-header|server-header|code]" + " [input_file output_file]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Converts XML protocol descriptions supplied on " - "stdin to client headers,\n" - "server headers, or protocol marshalling code.\n"); + "stdin or input file to client\n" + "headers, server headers, or protocol marshalling code.\n"); exit(ret); } @@ -1252,6 +1253,7 @@ int main(int argc, char *argv[]) { struct parse_context ctx; struct protocol protocol; + FILE *input = stdin; int len; void *buf; enum { @@ -1260,7 +1262,7 @@ int main(int argc, char *argv[]) CODE, } mode; - if (argc != 2) + if (argc != 2 && argc != 4) usage(EXIT_FAILURE); else if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0) usage(EXIT_SUCCESS); @@ -1273,6 +1275,20 @@ int main(int argc, char *argv[]) else usage(EXIT_FAILURE); + if (argc == 4) { + input = fopen(argv[2], "r"); + if (input == NULL) { + fprintf(stderr, "Could not open input file: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + if (freopen(argv[3], "w", stdout) == NULL) { + fprintf(stderr, "Could not open output file: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + } + wl_list_init(&protocol.interface_list); protocol.type_index = 0; protocol.null_run_length = 0; @@ -1293,7 +1309,7 @@ int main(int argc, char *argv[]) do { buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE); - len = fread(buf, 1, XML_BUFFER_SIZE, stdin); + len = fread(buf, 1, XML_BUFFER_SIZE, input); if (len < 0) { fprintf(stderr, "fread: %m\n"); exit(EXIT_FAILURE); From c45be3d21e7231eec33c50f38d85fb4ac5fb74cc Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Mon, 30 Mar 2015 06:10:22 -0400 Subject: [PATCH 0135/1152] protocol: add better description of wl_pointer.release Add note about what all wl_pointer.release does. Mainly that it destroys the proxy object, so programmer must not call wl_pointer_destroy() on the pointer any further. Signed-off-by: Marek Chalupa Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 041e5f09..f52677f8 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1560,7 +1560,13 @@ - + + Using this request client can tell the server that it is not going to + use the pointer object anymore. + + This request destroys the pointer proxy object, so user must not call + wl_pointer_destroy() after using this request. + From 313b26f415d48e1918818cb9da54f8e8bc521f87 Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Thu, 2 Apr 2015 19:20:00 -0700 Subject: [PATCH 0136/1152] config: use simpler regexp syntax to get dot version I wasted a lot of time before I figured out that I needed to add those square brackets to get this to work. Sigh... Reviewed-by: Bryce Harrington --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6bbec59b..271eec3e 100644 --- a/configure.ac +++ b/configure.ac @@ -141,7 +141,7 @@ if test "x$enable_documentation" = "xyes"; then AC_MSG_ERROR([Documentation build requested but graphviz's dot not found. Install graphviz or disable the documentation using --disable-documentation]) fi AC_MSG_CHECKING([for compatible dot version]) - dot_version=`$DOT -V 2>&1|$GREP -oP '(?<=version\W)@<:@0-9.@:>@*(?=\W(.*))'` + dot_version=`$DOT -V 2>&1|$GREP -o ['[0-9]*\.[0-9]*\.[0-9]*']` AS_VERSION_COMPARE([$dot_version], [2.26.0], [AC_MSG_RESULT([no]) AC_MSG_ERROR([Graphviz dot $dot_version too old. Graphviz 2.26+ required for documentation build. Install required graphviz version or disable the documentation using --disable-documentation])], From 0583ce741ed16315af591e9e4547a1e3d2c26e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 19 Mar 2015 16:56:23 +0800 Subject: [PATCH 0137/1152] scanner: Fail on empty enumerations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this patch, the scanner would generate invalid C which wouldn't compile anyway, so lets be nice and fail earlier and point out where the error is. Signed-off-by: Jonas Ådahl Reviewed-by: Derek Foreman Reviewed-by: David Fort Reviewed-by: Pekka Paalanen --- src/scanner.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index efdc69c6..adc9aa3b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -552,6 +552,10 @@ end_element(void *data, const XML_Char *name) strcmp(name, "event") == 0) { ctx->message = NULL; } else if (strcmp(name, "enum") == 0) { + if (wl_list_empty(&ctx->enumeration->entry_list)) { + fail(&ctx->loc, "enumeration %s was empty", + ctx->enumeration->name); + } ctx->enumeration = NULL; } } From 70d3c0fe8a49ae2317ed5baaf2e3062d73cae6f4 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 15 Apr 2015 15:06:27 -0700 Subject: [PATCH 0138/1152] tests: Typo in a comment (Spotted by Silvan) Signed-off-by: Bryce Harrington --- tests/test-compositor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 89c41407..1caea18c 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -471,7 +471,7 @@ client_disconnect(struct client *c) } /* num is number of clients that requests to stop display. - * Display is stopped after it receive num STOP_DISPLAY requests */ + * Display is stopped after it receives num STOP_DISPLAY requests */ int stop_display(struct client *c, int num) { From d74a9c079b1aeb44f69b4132dc2c38362e21f281 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Wed, 29 Apr 2015 16:34:47 +0300 Subject: [PATCH 0139/1152] introduce new headers wayland-client-core.h and wayland-server-core.h wayland-client.h and wayland-server.h include the protocol headers generated at build time. This means that a libwayland user cannot generate and use protocol code created from a wayland.xml newer than the installed libwayland, because it is not possible to only include the API header. Another use case is language bindings, which would generate their own protocol code and which only need to use the library ABI, not the generated C code. This commit adds wayland-client-core.h and wayland-server-core.h which do not include the protocol headers or any deprecated code. Reviewed-by: Jason Ekstrand Reviewed-by: Pekka Paalanen --- Makefile.am | 2 + doc/doxygen/Makefile.am | 7 +- src/wayland-client-core.h | 180 +++++++++++++++++ src/wayland-client.h | 162 +-------------- src/wayland-server-core.h | 405 ++++++++++++++++++++++++++++++++++++++ src/wayland-server.h | 384 ++---------------------------------- 6 files changed, 611 insertions(+), 529 deletions(-) create mode 100644 src/wayland-client-core.h create mode 100644 src/wayland-server-core.h diff --git a/Makefile.am b/Makefile.am index 0fccf863..a8a0a56e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,9 @@ noinst_LTLIBRARIES = libwayland-util.la include_HEADERS = \ src/wayland-util.h \ src/wayland-server.h \ + src/wayland-server-core.h \ src/wayland-client.h \ + src/wayland-client-core.h \ src/wayland-egl.h \ src/wayland-version.h diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index edf36526..5520d396 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -11,18 +11,21 @@ scanned_src_files_shared = \ scanned_src_files_Client = \ $(scanned_src_files_shared) \ $(top_srcdir)/src/wayland-client.c \ - $(top_srcdir)/src/wayland-client.h + $(top_srcdir)/src/wayland-client.h \ + $(top_srcdir)/src/wayland-client-core.h scanned_src_files_Server = \ $(scanned_src_files_shared) \ $(top_srcdir)/src/wayland-server.c \ $(top_srcdir)/src/wayland-server.h \ + $(top_srcdir)/src/wayland-server-core.h \ $(top_srcdir)/src/wayland-shm.c scanned_src_files_man = \ $(scanned_src_files_Server) \ $(top_srcdir)/src/wayland-client.c \ - $(top_srcdir)/src/wayland-client.h + $(top_srcdir)/src/wayland-client.h \ + $(top_srcdir)/src/wayland-client-core.h diagramsdir := $(srcdir)/dot diagramssrc := $(wildcard $(diagramsdir)/*.gv) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h new file mode 100644 index 00000000..d7a0d9ed --- /dev/null +++ b/src/wayland-client-core.h @@ -0,0 +1,180 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef WAYLAND_CLIENT_CORE_H +#define WAYLAND_CLIENT_CORE_H + +#include "wayland-util.h" +#include "wayland-version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \class wl_proxy + * + * \brief Represents a protocol object on the client side. + * + * A wl_proxy acts as a client side proxy to an object existing in the + * compositor. The proxy is responsible for converting requests made by the + * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events + * coming from the compositor are also handled by the proxy, which will in + * turn call the handler set with \ref wl_proxy_add_listener(). + * + * \note With the exception of function \ref wl_proxy_set_queue(), functions + * accessing a wl_proxy are not normally used by client code. Clients + * should normally use the higher level interface generated by the scanner to + * interact with compositor objects. + * + */ +struct wl_proxy; + +/** \class wl_display + * + * \brief Represents a connection to the compositor and acts as a proxy to + * the wl_display singleton object. + * + * A wl_display object represents a client connection to a Wayland + * compositor. It is created with either \ref wl_display_connect() or + * \ref wl_display_connect_to_fd(). A connection is terminated using + * \ref wl_display_disconnect(). + * + * A wl_display is also used as the \ref wl_proxy for the wl_display + * singleton object on the compositor side. + * + * A wl_display object handles all the data sent from and to the + * compositor. When a \ref wl_proxy marshals a request, it will write its wire + * representation to the display's write buffer. The data is sent to the + * compositor when the client calls \ref wl_display_flush(). + * + * Incoming data is handled in two steps: queueing and dispatching. In the + * queue step, the data coming from the display fd is interpreted and + * added to a queue. On the dispatch step, the handler for the incoming + * event set by the client on the corresponding \ref wl_proxy is called. + * + * A wl_display has at least one event queue, called the default + * queue. Clients can create additional event queues with \ref + * wl_display_create_queue() and assign \ref wl_proxy's to it. Events + * occurring in a particular proxy are always queued in its assigned queue. + * A client can ensure that a certain assumption, such as holding a lock + * or running from a given thread, is true when a proxy event handler is + * called by assigning that proxy to an event queue and making sure that + * this queue is only dispatched when the assumption holds. + * + * The default queue is dispatched by calling \ref wl_display_dispatch(). + * This will dispatch any events queued on the default queue and attempt + * to read from the display fd if it's empty. Events read are then queued + * on the appropriate queues according to the proxy assignment. + * + * A user created queue is dispatched with \ref wl_display_dispatch_queue(). + * This function behaves exactly the same as wl_display_dispatch() + * but it dispatches given queue instead of the default queue. + * + * A real world example of event queue usage is Mesa's implementation of + * eglSwapBuffers() for the Wayland platform. This function might need + * to block until a frame callback is received, but dispatching the default + * queue could cause an event handler on the client to start drawing + * again. This problem is solved using another event queue, so that only + * the events handled by the EGL code are dispatched during the block. + * + * This creates a problem where a thread dispatches a non-default + * queue, reading all the data from the display fd. If the application + * would call \em poll(2) after that it would block, even though there + * might be events queued on the default queue. Those events should be + * dispatched with \ref wl_display_dispatch_(queue_)pending() before + * flushing and blocking. + */ +struct wl_display; + +/** \class wl_event_queue + * + * \brief A queue for \ref wl_proxy object events. + * + * Event queues allows the events on a display to be handled in a thread-safe + * manner. See \ref wl_display for details. + * + */ +struct wl_event_queue; + +void wl_event_queue_destroy(struct wl_event_queue *queue); + +void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); +void wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode, + union wl_argument *args); +struct wl_proxy *wl_proxy_create(struct wl_proxy *factory, + const struct wl_interface *interface); +struct wl_proxy *wl_proxy_marshal_constructor(struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface, + ...); +struct wl_proxy * +wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, + uint32_t opcode, union wl_argument *args, + const struct wl_interface *interface); + +void wl_proxy_destroy(struct wl_proxy *proxy); +int wl_proxy_add_listener(struct wl_proxy *proxy, + void (**implementation)(void), void *data); +const void *wl_proxy_get_listener(struct wl_proxy *proxy); +int wl_proxy_add_dispatcher(struct wl_proxy *proxy, + wl_dispatcher_func_t dispatcher_func, + const void * dispatcher_data, void *data); +void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); +void *wl_proxy_get_user_data(struct wl_proxy *proxy); +uint32_t wl_proxy_get_id(struct wl_proxy *proxy); +const char *wl_proxy_get_class(struct wl_proxy *proxy); +void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); + +struct wl_display *wl_display_connect(const char *name); +struct wl_display *wl_display_connect_to_fd(int fd); +void wl_display_disconnect(struct wl_display *display); +int wl_display_get_fd(struct wl_display *display); +int wl_display_dispatch(struct wl_display *display); +int wl_display_dispatch_queue(struct wl_display *display, + struct wl_event_queue *queue); +int wl_display_dispatch_queue_pending(struct wl_display *display, + struct wl_event_queue *queue); +int wl_display_dispatch_pending(struct wl_display *display); +int wl_display_get_error(struct wl_display *display); +uint32_t wl_display_get_protocol_error(struct wl_display *display, + const struct wl_interface **interface, + uint32_t *id); + +int wl_display_flush(struct wl_display *display); +int wl_display_roundtrip_queue(struct wl_display *display, + struct wl_event_queue *queue); +int wl_display_roundtrip(struct wl_display *display); +struct wl_event_queue *wl_display_create_queue(struct wl_display *display); + +int wl_display_prepare_read_queue(struct wl_display *display, + struct wl_event_queue *queue); +int wl_display_prepare_read(struct wl_display *display); +void wl_display_cancel_read(struct wl_display *display); +int wl_display_read_events(struct wl_display *display); + +void wl_log_set_handler_client(wl_log_func_t handler); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland-client.h b/src/wayland-client.h index 71cd822f..37b0d7f2 100644 --- a/src/wayland-client.h +++ b/src/wayland-client.h @@ -20,163 +20,17 @@ * OF THIS SOFTWARE. */ + +/** Use of this header file is discouraged. Prefer including + * wayland-client-core.h instead, which does not include the + * client protocol header and as such only defines the library + * API. + */ + #ifndef WAYLAND_CLIENT_H #define WAYLAND_CLIENT_H -#include "wayland-util.h" -#include "wayland-version.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** \class wl_proxy - * - * \brief Represents a protocol object on the client side. - * - * A wl_proxy acts as a client side proxy to an object existing in the - * compositor. The proxy is responsible for converting requests made by the - * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events - * coming from the compositor are also handled by the proxy, which will in - * turn call the handler set with \ref wl_proxy_add_listener(). - * - * \note With the exception of function \ref wl_proxy_set_queue(), functions - * accessing a wl_proxy are not normally used by client code. Clients - * should normally use the higher level interface generated by the scanner to - * interact with compositor objects. - * - */ -struct wl_proxy; - -/** \class wl_display - * - * \brief Represents a connection to the compositor and acts as a proxy to - * the wl_display singleton object. - * - * A wl_display object represents a client connection to a Wayland - * compositor. It is created with either \ref wl_display_connect() or - * \ref wl_display_connect_to_fd(). A connection is terminated using - * \ref wl_display_disconnect(). - * - * A wl_display is also used as the \ref wl_proxy for the wl_display - * singleton object on the compositor side. - * - * A wl_display object handles all the data sent from and to the - * compositor. When a \ref wl_proxy marshals a request, it will write its wire - * representation to the display's write buffer. The data is sent to the - * compositor when the client calls \ref wl_display_flush(). - * - * Incoming data is handled in two steps: queueing and dispatching. In the - * queue step, the data coming from the display fd is interpreted and - * added to a queue. On the dispatch step, the handler for the incoming - * event set by the client on the corresponding \ref wl_proxy is called. - * - * A wl_display has at least one event queue, called the default - * queue. Clients can create additional event queues with \ref - * wl_display_create_queue() and assign \ref wl_proxy's to it. Events - * occurring in a particular proxy are always queued in its assigned queue. - * A client can ensure that a certain assumption, such as holding a lock - * or running from a given thread, is true when a proxy event handler is - * called by assigning that proxy to an event queue and making sure that - * this queue is only dispatched when the assumption holds. - * - * The default queue is dispatched by calling \ref wl_display_dispatch(). - * This will dispatch any events queued on the default queue and attempt - * to read from the display fd if it's empty. Events read are then queued - * on the appropriate queues according to the proxy assignment. - * - * A user created queue is dispatched with \ref wl_display_dispatch_queue(). - * This function behaves exactly the same as wl_display_dispatch() - * but it dispatches given queue instead of the default queue. - * - * A real world example of event queue usage is Mesa's implementation of - * eglSwapBuffers() for the Wayland platform. This function might need - * to block until a frame callback is received, but dispatching the default - * queue could cause an event handler on the client to start drawing - * again. This problem is solved using another event queue, so that only - * the events handled by the EGL code are dispatched during the block. - * - * This creates a problem where a thread dispatches a non-default - * queue, reading all the data from the display fd. If the application - * would call \em poll(2) after that it would block, even though there - * might be events queued on the default queue. Those events should be - * dispatched with \ref wl_display_dispatch_(queue_)pending() before - * flushing and blocking. - */ -struct wl_display; - -/** \class wl_event_queue - * - * \brief A queue for \ref wl_proxy object events. - * - * Event queues allows the events on a display to be handled in a thread-safe - * manner. See \ref wl_display for details. - * - */ -struct wl_event_queue; - -void wl_event_queue_destroy(struct wl_event_queue *queue); - -void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); -void wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode, - union wl_argument *args); -struct wl_proxy *wl_proxy_create(struct wl_proxy *factory, - const struct wl_interface *interface); -struct wl_proxy *wl_proxy_marshal_constructor(struct wl_proxy *proxy, - uint32_t opcode, - const struct wl_interface *interface, - ...); -struct wl_proxy * -wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, - uint32_t opcode, union wl_argument *args, - const struct wl_interface *interface); - -void wl_proxy_destroy(struct wl_proxy *proxy); -int wl_proxy_add_listener(struct wl_proxy *proxy, - void (**implementation)(void), void *data); -const void *wl_proxy_get_listener(struct wl_proxy *proxy); -int wl_proxy_add_dispatcher(struct wl_proxy *proxy, - wl_dispatcher_func_t dispatcher_func, - const void * dispatcher_data, void *data); -void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); -void *wl_proxy_get_user_data(struct wl_proxy *proxy); -uint32_t wl_proxy_get_id(struct wl_proxy *proxy); -const char *wl_proxy_get_class(struct wl_proxy *proxy); -void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); - +#include "wayland-client-core.h" #include "wayland-client-protocol.h" -struct wl_display *wl_display_connect(const char *name); -struct wl_display *wl_display_connect_to_fd(int fd); -void wl_display_disconnect(struct wl_display *display); -int wl_display_get_fd(struct wl_display *display); -int wl_display_dispatch(struct wl_display *display); -int wl_display_dispatch_queue(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_dispatch_queue_pending(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_dispatch_pending(struct wl_display *display); -int wl_display_get_error(struct wl_display *display); -uint32_t wl_display_get_protocol_error(struct wl_display *display, - const struct wl_interface **interface, - uint32_t *id); - -int wl_display_flush(struct wl_display *display); -int wl_display_roundtrip_queue(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_roundtrip(struct wl_display *display); -struct wl_event_queue *wl_display_create_queue(struct wl_display *display); - -int wl_display_prepare_read_queue(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_prepare_read(struct wl_display *display); -void wl_display_cancel_read(struct wl_display *display); -int wl_display_read_events(struct wl_display *display); - -void wl_log_set_handler_client(wl_log_func_t handler); - -#ifdef __cplusplus -} -#endif - #endif diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h new file mode 100644 index 00000000..7d037892 --- /dev/null +++ b/src/wayland-server-core.h @@ -0,0 +1,405 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef WAYLAND_SERVER_CORE_H +#define WAYLAND_SERVER_CORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-util.h" +#include "wayland-version.h" + +enum { + WL_EVENT_READABLE = 0x01, + WL_EVENT_WRITABLE = 0x02, + WL_EVENT_HANGUP = 0x04, + WL_EVENT_ERROR = 0x08 +}; + +struct wl_event_loop; +struct wl_event_source; +typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data); +typedef int (*wl_event_loop_timer_func_t)(void *data); +typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data); +typedef void (*wl_event_loop_idle_func_t)(void *data); + +struct wl_event_loop *wl_event_loop_create(void); +void wl_event_loop_destroy(struct wl_event_loop *loop); +struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop, + int fd, uint32_t mask, + wl_event_loop_fd_func_t func, + void *data); +int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask); +struct wl_event_source *wl_event_loop_add_timer(struct wl_event_loop *loop, + wl_event_loop_timer_func_t func, + void *data); +struct wl_event_source * +wl_event_loop_add_signal(struct wl_event_loop *loop, + int signal_number, + wl_event_loop_signal_func_t func, + void *data); + +int wl_event_source_timer_update(struct wl_event_source *source, + int ms_delay); +int wl_event_source_remove(struct wl_event_source *source); +void wl_event_source_check(struct wl_event_source *source); + + +int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout); +void wl_event_loop_dispatch_idle(struct wl_event_loop *loop); +struct wl_event_source *wl_event_loop_add_idle(struct wl_event_loop *loop, + wl_event_loop_idle_func_t func, + void *data); +int wl_event_loop_get_fd(struct wl_event_loop *loop); + +struct wl_client; +struct wl_display; +struct wl_listener; +struct wl_resource; +struct wl_global; +typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data); + +void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, + struct wl_listener * listener); +struct wl_listener *wl_event_loop_get_destroy_listener( + struct wl_event_loop *loop, + wl_notify_func_t notify); + +struct wl_display *wl_display_create(void); +void wl_display_destroy(struct wl_display *display); +struct wl_event_loop *wl_display_get_event_loop(struct wl_display *display); +int wl_display_add_socket(struct wl_display *display, const char *name); +const char *wl_display_add_socket_auto(struct wl_display *display); +void wl_display_terminate(struct wl_display *display); +void wl_display_run(struct wl_display *display); +void wl_display_flush_clients(struct wl_display *display); + +typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, + uint32_t version, uint32_t id); + +uint32_t wl_display_get_serial(struct wl_display *display); +uint32_t wl_display_next_serial(struct wl_display *display); + +void wl_display_add_destroy_listener(struct wl_display *display, + struct wl_listener *listener); +struct wl_listener *wl_display_get_destroy_listener(struct wl_display *display, + wl_notify_func_t notify); + +struct wl_global *wl_global_create(struct wl_display *display, + const struct wl_interface *interface, + int version, + void *data, wl_global_bind_func_t bind); +void wl_global_destroy(struct wl_global *global); + +struct wl_client *wl_client_create(struct wl_display *display, int fd); +void wl_client_destroy(struct wl_client *client); +void wl_client_flush(struct wl_client *client); +void wl_client_get_credentials(struct wl_client *client, + pid_t *pid, uid_t *uid, gid_t *gid); + +void wl_client_add_destroy_listener(struct wl_client *client, + struct wl_listener *listener); +struct wl_listener *wl_client_get_destroy_listener(struct wl_client *client, + wl_notify_func_t notify); + +struct wl_resource * +wl_client_get_object(struct wl_client *client, uint32_t id); +void +wl_client_post_no_memory(struct wl_client *client); + +/** \class wl_listener + * + * \brief A single listener for Wayland signals + * + * wl_listener provides the means to listen for wl_signal notifications. Many + * Wayland objects use wl_listener for notification of significant events like + * object destruction. + * + * Clients should create wl_listener objects manually and can register them as + * listeners to signals using #wl_signal_add, assuming the signal is + * directly accessible. For opaque structs like wl_event_loop, adding a + * listener should be done through provided accessor methods. A listener can + * only listen to one signal at a time. + * + * \code + * struct wl_listener your_listener; + * + * your_listener.notify = your_callback_method; + * + * // Direct access + * wl_signal_add(&some_object->destroy_signal, &your_listener); + * + * // Accessor access + * wl_event_loop *loop = ...; + * wl_event_loop_add_destroy_listener(loop, &your_listener); + * \endcode + * + * If the listener is part of a larger struct, #wl_container_of can be used + * to retrieve a pointer to it: + * + * \code + * void your_listener(struct wl_listener *listener, void *data) + * { + * struct your_data *data; + * + * your_data = wl_container_of(listener, data, your_member_name); + * } + * \endcode + * + * If you need to remove a listener from a signal, use wl_list_remove(). + * + * \code + * wl_list_remove(&your_listener.link); + * \endcode + * + * \sa wl_signal + */ +struct wl_listener { + struct wl_list link; + wl_notify_func_t notify; +}; + +/** \class wl_signal + * + * \brief A source of a type of observable event + * + * Signals are recognized points where significant events can be observed. + * Compositors as well as the server can provide signals. Observers are + * wl_listener's that are added through #wl_signal_add. Signals are emitted + * using #wl_signal_emit, which will invoke all listeners until that + * listener is removed by wl_list_remove() (or whenever the signal is + * destroyed). + * + * \sa wl_listener for more information on using wl_signal + */ +struct wl_signal { + struct wl_list listener_list; +}; + +/** Initialize a new \ref wl_signal for use. + * + * \param signal The signal that will be initialized + * + * \memberof wl_signal + */ +static inline void +wl_signal_init(struct wl_signal *signal) +{ + wl_list_init(&signal->listener_list); +} + +/** Add the specified listener to this signal. + * + * \param signal The signal that will emit events to the listener + * \param listener The listener to add + * + * \memberof wl_signal + */ +static inline void +wl_signal_add(struct wl_signal *signal, struct wl_listener *listener) +{ + wl_list_insert(signal->listener_list.prev, &listener->link); +} + +/** Gets the listener struct for the specified callback. + * + * \param signal The signal that contains the specified listener + * \param notify The listener that is the target of this search + * \return the list item that corresponds to the specified listener, or NULL + * if none was found + * + * \memberof wl_signal + */ +static inline struct wl_listener * +wl_signal_get(struct wl_signal *signal, wl_notify_func_t notify) +{ + struct wl_listener *l; + + wl_list_for_each(l, &signal->listener_list, link) + if (l->notify == notify) + return l; + + return NULL; +} + +/** Emits this signal, notifying all registered listeners. + * + * \param signal The signal object that will emit the signal + * \param data The data that will be emitted with the signal + * + * \memberof wl_signal + */ +static inline void +wl_signal_emit(struct wl_signal *signal, void *data) +{ + struct wl_listener *l, *next; + + wl_list_for_each_safe(l, next, &signal->listener_list, link) + l->notify(l, data); +} + +typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource); + +/* + * Post an event to the client's object referred to by 'resource'. + * 'opcode' is the event number generated from the protocol XML + * description (the event name). The variable arguments are the event + * parameters, in the order they appear in the protocol XML specification. + * + * The variable arguments' types are: + * - type=uint: uint32_t + * - type=int: int32_t + * - type=fixed: wl_fixed_t + * - type=string: (const char *) to a nil-terminated string + * - type=array: (struct wl_array *) + * - type=fd: int, that is an open file descriptor + * - type=new_id: (struct wl_object *) or (struct wl_resource *) + * - type=object: (struct wl_object *) or (struct wl_resource *) + */ +void wl_resource_post_event(struct wl_resource *resource, + uint32_t opcode, ...); +void wl_resource_post_event_array(struct wl_resource *resource, + uint32_t opcode, union wl_argument *args); +void wl_resource_queue_event(struct wl_resource *resource, + uint32_t opcode, ...); +void wl_resource_queue_event_array(struct wl_resource *resource, + uint32_t opcode, union wl_argument *args); + +/* msg is a printf format string, variable args are its args. */ +void wl_resource_post_error(struct wl_resource *resource, + uint32_t code, const char *msg, ...) + __attribute__ ((format (printf, 3, 4))); +void wl_resource_post_no_memory(struct wl_resource *resource); + +struct wl_display * +wl_client_get_display(struct wl_client *client); + +struct wl_resource * +wl_resource_create(struct wl_client *client, + const struct wl_interface *interface, + int version, uint32_t id); +void +wl_resource_set_implementation(struct wl_resource *resource, + const void *implementation, + void *data, + wl_resource_destroy_func_t destroy); +void +wl_resource_set_dispatcher(struct wl_resource *resource, + wl_dispatcher_func_t dispatcher, + const void *implementation, + void *data, + wl_resource_destroy_func_t destroy); + +void +wl_resource_destroy(struct wl_resource *resource); +uint32_t +wl_resource_get_id(struct wl_resource *resource); +struct wl_list * +wl_resource_get_link(struct wl_resource *resource); +struct wl_resource * +wl_resource_from_link(struct wl_list *resource); +struct wl_resource * +wl_resource_find_for_client(struct wl_list *list, struct wl_client *client); +struct wl_client * +wl_resource_get_client(struct wl_resource *resource); +void +wl_resource_set_user_data(struct wl_resource *resource, void *data); +void * +wl_resource_get_user_data(struct wl_resource *resource); +int +wl_resource_get_version(struct wl_resource *resource); +void +wl_resource_set_destructor(struct wl_resource *resource, + wl_resource_destroy_func_t destroy); +int +wl_resource_instance_of(struct wl_resource *resource, + const struct wl_interface *interface, + const void *implementation); + +void +wl_resource_add_destroy_listener(struct wl_resource *resource, + struct wl_listener * listener); +struct wl_listener * +wl_resource_get_destroy_listener(struct wl_resource *resource, + wl_notify_func_t notify); + +#define wl_resource_for_each(resource, list) \ + for (resource = 0, resource = wl_resource_from_link((list)->next); \ + wl_resource_get_link(resource) != (list); \ + resource = wl_resource_from_link(wl_resource_get_link(resource)->next)) + +#define wl_resource_for_each_safe(resource, tmp, list) \ + for (resource = 0, tmp = 0, \ + resource = wl_resource_from_link((list)->next), \ + tmp = wl_resource_from_link((list)->next->next); \ + wl_resource_get_link(resource) != (list); \ + resource = tmp, \ + tmp = wl_resource_from_link(wl_resource_get_link(resource)->next)) + +struct wl_shm_buffer; + +void +wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer); + +void +wl_shm_buffer_end_access(struct wl_shm_buffer *buffer); + +struct wl_shm_buffer * +wl_shm_buffer_get(struct wl_resource *resource); + +void * +wl_shm_buffer_get_data(struct wl_shm_buffer *buffer); + +int32_t +wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer); + +uint32_t +wl_shm_buffer_get_format(struct wl_shm_buffer *buffer); + +int32_t +wl_shm_buffer_get_width(struct wl_shm_buffer *buffer); + +int32_t +wl_shm_buffer_get_height(struct wl_shm_buffer *buffer); + +int +wl_display_init_shm(struct wl_display *display); + +uint32_t * +wl_display_add_shm_format(struct wl_display *display, uint32_t format); + +struct wl_shm_buffer * +wl_shm_buffer_create(struct wl_client *client, + uint32_t id, int32_t width, int32_t height, + int32_t stride, uint32_t format); + +void wl_log_set_handler_server(wl_log_func_t handler); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland-server.h b/src/wayland-server.h index af2f03d5..9fe19f50 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -20,249 +20,22 @@ * OF THIS SOFTWARE. */ + +/** Use of this header file is discouraged. Prefer including + * wayland-server-core.h instead, which does not include the + * client protocol header and as such only defines the library + * API, excluding the deprecated API below. + */ + #ifndef WAYLAND_SERVER_H #define WAYLAND_SERVER_H +#include "wayland-server-core.h" + #ifdef __cplusplus extern "C" { #endif -#include -#include -#include "wayland-util.h" -#include "wayland-version.h" - -enum { - WL_EVENT_READABLE = 0x01, - WL_EVENT_WRITABLE = 0x02, - WL_EVENT_HANGUP = 0x04, - WL_EVENT_ERROR = 0x08 -}; - -struct wl_event_loop; -struct wl_event_source; -typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data); -typedef int (*wl_event_loop_timer_func_t)(void *data); -typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data); -typedef void (*wl_event_loop_idle_func_t)(void *data); - -struct wl_event_loop *wl_event_loop_create(void); -void wl_event_loop_destroy(struct wl_event_loop *loop); -struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop, - int fd, uint32_t mask, - wl_event_loop_fd_func_t func, - void *data); -int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask); -struct wl_event_source *wl_event_loop_add_timer(struct wl_event_loop *loop, - wl_event_loop_timer_func_t func, - void *data); -struct wl_event_source * -wl_event_loop_add_signal(struct wl_event_loop *loop, - int signal_number, - wl_event_loop_signal_func_t func, - void *data); - -int wl_event_source_timer_update(struct wl_event_source *source, - int ms_delay); -int wl_event_source_remove(struct wl_event_source *source); -void wl_event_source_check(struct wl_event_source *source); - - -int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout); -void wl_event_loop_dispatch_idle(struct wl_event_loop *loop); -struct wl_event_source *wl_event_loop_add_idle(struct wl_event_loop *loop, - wl_event_loop_idle_func_t func, - void *data); -int wl_event_loop_get_fd(struct wl_event_loop *loop); - -struct wl_client; -struct wl_display; -struct wl_listener; -struct wl_resource; -struct wl_global; -typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data); - -void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, - struct wl_listener * listener); -struct wl_listener *wl_event_loop_get_destroy_listener( - struct wl_event_loop *loop, - wl_notify_func_t notify); - -struct wl_display *wl_display_create(void); -void wl_display_destroy(struct wl_display *display); -struct wl_event_loop *wl_display_get_event_loop(struct wl_display *display); -int wl_display_add_socket(struct wl_display *display, const char *name); -const char *wl_display_add_socket_auto(struct wl_display *display); -void wl_display_terminate(struct wl_display *display); -void wl_display_run(struct wl_display *display); -void wl_display_flush_clients(struct wl_display *display); - -typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, - uint32_t version, uint32_t id); - -uint32_t wl_display_get_serial(struct wl_display *display); -uint32_t wl_display_next_serial(struct wl_display *display); - -void wl_display_add_destroy_listener(struct wl_display *display, - struct wl_listener *listener); -struct wl_listener *wl_display_get_destroy_listener(struct wl_display *display, - wl_notify_func_t notify); - -struct wl_global *wl_global_create(struct wl_display *display, - const struct wl_interface *interface, - int version, - void *data, wl_global_bind_func_t bind); -void wl_global_destroy(struct wl_global *global); - -struct wl_client *wl_client_create(struct wl_display *display, int fd); -void wl_client_destroy(struct wl_client *client); -void wl_client_flush(struct wl_client *client); -void wl_client_get_credentials(struct wl_client *client, - pid_t *pid, uid_t *uid, gid_t *gid); - -void wl_client_add_destroy_listener(struct wl_client *client, - struct wl_listener *listener); -struct wl_listener *wl_client_get_destroy_listener(struct wl_client *client, - wl_notify_func_t notify); - -struct wl_resource * -wl_client_get_object(struct wl_client *client, uint32_t id); -void -wl_client_post_no_memory(struct wl_client *client); - -/** \class wl_listener - * - * \brief A single listener for Wayland signals - * - * wl_listener provides the means to listen for wl_signal notifications. Many - * Wayland objects use wl_listener for notification of significant events like - * object destruction. - * - * Clients should create wl_listener objects manually and can register them as - * listeners to signals using #wl_signal_add, assuming the signal is - * directly accessible. For opaque structs like wl_event_loop, adding a - * listener should be done through provided accessor methods. A listener can - * only listen to one signal at a time. - * - * \code - * struct wl_listener your_listener; - * - * your_listener.notify = your_callback_method; - * - * // Direct access - * wl_signal_add(&some_object->destroy_signal, &your_listener); - * - * // Accessor access - * wl_event_loop *loop = ...; - * wl_event_loop_add_destroy_listener(loop, &your_listener); - * \endcode - * - * If the listener is part of a larger struct, #wl_container_of can be used - * to retrieve a pointer to it: - * - * \code - * void your_listener(struct wl_listener *listener, void *data) - * { - * struct your_data *data; - * - * your_data = wl_container_of(listener, data, your_member_name); - * } - * \endcode - * - * If you need to remove a listener from a signal, use wl_list_remove(). - * - * \code - * wl_list_remove(&your_listener.link); - * \endcode - * - * \sa wl_signal - */ -struct wl_listener { - struct wl_list link; - wl_notify_func_t notify; -}; - -/** \class wl_signal - * - * \brief A source of a type of observable event - * - * Signals are recognized points where significant events can be observed. - * Compositors as well as the server can provide signals. Observers are - * wl_listener's that are added through #wl_signal_add. Signals are emitted - * using #wl_signal_emit, which will invoke all listeners until that - * listener is removed by wl_list_remove() (or whenever the signal is - * destroyed). - * - * \sa wl_listener for more information on using wl_signal - */ -struct wl_signal { - struct wl_list listener_list; -}; - -/** Initialize a new \ref wl_signal for use. - * - * \param signal The signal that will be initialized - * - * \memberof wl_signal - */ -static inline void -wl_signal_init(struct wl_signal *signal) -{ - wl_list_init(&signal->listener_list); -} - -/** Add the specified listener to this signal. - * - * \param signal The signal that will emit events to the listener - * \param listener The listener to add - * - * \memberof wl_signal - */ -static inline void -wl_signal_add(struct wl_signal *signal, struct wl_listener *listener) -{ - wl_list_insert(signal->listener_list.prev, &listener->link); -} - -/** Gets the listener struct for the specified callback. - * - * \param signal The signal that contains the specified listener - * \param notify The listener that is the target of this search - * \return the list item that corresponds to the specified listener, or NULL - * if none was found - * - * \memberof wl_signal - */ -static inline struct wl_listener * -wl_signal_get(struct wl_signal *signal, wl_notify_func_t notify) -{ - struct wl_listener *l; - - wl_list_for_each(l, &signal->listener_list, link) - if (l->notify == notify) - return l; - - return NULL; -} - -/** Emits this signal, notifying all registered listeners. - * - * \param signal The signal object that will emit the signal - * \param data The data that will be emitted with the signal - * - * \memberof wl_signal - */ -static inline void -wl_signal_emit(struct wl_signal *signal, void *data) -{ - struct wl_listener *l, *next; - - wl_list_for_each_safe(l, next, &signal->listener_list, link) - l->notify(l, data); -} - -typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource); - #ifndef WL_HIDE_DEPRECATED struct wl_object { @@ -313,145 +86,10 @@ wl_display_remove_global(struct wl_display *display, #endif -/* - * Post an event to the client's object referred to by 'resource'. - * 'opcode' is the event number generated from the protocol XML - * description (the event name). The variable arguments are the event - * parameters, in the order they appear in the protocol XML specification. - * - * The variable arguments' types are: - * - type=uint: uint32_t - * - type=int: int32_t - * - type=fixed: wl_fixed_t - * - type=string: (const char *) to a nil-terminated string - * - type=array: (struct wl_array *) - * - type=fd: int, that is an open file descriptor - * - type=new_id: (struct wl_object *) or (struct wl_resource *) - * - type=object: (struct wl_object *) or (struct wl_resource *) - */ -void wl_resource_post_event(struct wl_resource *resource, - uint32_t opcode, ...); -void wl_resource_post_event_array(struct wl_resource *resource, - uint32_t opcode, union wl_argument *args); -void wl_resource_queue_event(struct wl_resource *resource, - uint32_t opcode, ...); -void wl_resource_queue_event_array(struct wl_resource *resource, - uint32_t opcode, union wl_argument *args); - -/* msg is a printf format string, variable args are its args. */ -void wl_resource_post_error(struct wl_resource *resource, - uint32_t code, const char *msg, ...) - __attribute__ ((format (printf, 3, 4))); -void wl_resource_post_no_memory(struct wl_resource *resource); - -#include "wayland-server-protocol.h" - -struct wl_display * -wl_client_get_display(struct wl_client *client); - -struct wl_resource * -wl_resource_create(struct wl_client *client, - const struct wl_interface *interface, - int version, uint32_t id); -void -wl_resource_set_implementation(struct wl_resource *resource, - const void *implementation, - void *data, - wl_resource_destroy_func_t destroy); -void -wl_resource_set_dispatcher(struct wl_resource *resource, - wl_dispatcher_func_t dispatcher, - const void *implementation, - void *data, - wl_resource_destroy_func_t destroy); - -void -wl_resource_destroy(struct wl_resource *resource); -uint32_t -wl_resource_get_id(struct wl_resource *resource); -struct wl_list * -wl_resource_get_link(struct wl_resource *resource); -struct wl_resource * -wl_resource_from_link(struct wl_list *resource); -struct wl_resource * -wl_resource_find_for_client(struct wl_list *list, struct wl_client *client); -struct wl_client * -wl_resource_get_client(struct wl_resource *resource); -void -wl_resource_set_user_data(struct wl_resource *resource, void *data); -void * -wl_resource_get_user_data(struct wl_resource *resource); -int -wl_resource_get_version(struct wl_resource *resource); -void -wl_resource_set_destructor(struct wl_resource *resource, - wl_resource_destroy_func_t destroy); -int -wl_resource_instance_of(struct wl_resource *resource, - const struct wl_interface *interface, - const void *implementation); - -void -wl_resource_add_destroy_listener(struct wl_resource *resource, - struct wl_listener * listener); -struct wl_listener * -wl_resource_get_destroy_listener(struct wl_resource *resource, - wl_notify_func_t notify); - -#define wl_resource_for_each(resource, list) \ - for (resource = 0, resource = wl_resource_from_link((list)->next); \ - wl_resource_get_link(resource) != (list); \ - resource = wl_resource_from_link(wl_resource_get_link(resource)->next)) - -#define wl_resource_for_each_safe(resource, tmp, list) \ - for (resource = 0, tmp = 0, \ - resource = wl_resource_from_link((list)->next), \ - tmp = wl_resource_from_link((list)->next->next); \ - wl_resource_get_link(resource) != (list); \ - resource = tmp, \ - tmp = wl_resource_from_link(wl_resource_get_link(resource)->next)) - -struct wl_shm_buffer; - -void -wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer); - -void -wl_shm_buffer_end_access(struct wl_shm_buffer *buffer); - -struct wl_shm_buffer * -wl_shm_buffer_get(struct wl_resource *resource); - -void * -wl_shm_buffer_get_data(struct wl_shm_buffer *buffer); - -int32_t -wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer); - -uint32_t -wl_shm_buffer_get_format(struct wl_shm_buffer *buffer); - -int32_t -wl_shm_buffer_get_width(struct wl_shm_buffer *buffer); - -int32_t -wl_shm_buffer_get_height(struct wl_shm_buffer *buffer); - -int -wl_display_init_shm(struct wl_display *display); - -uint32_t * -wl_display_add_shm_format(struct wl_display *display, uint32_t format); - -struct wl_shm_buffer * -wl_shm_buffer_create(struct wl_client *client, - uint32_t id, int32_t width, int32_t height, - int32_t stride, uint32_t format); - -void wl_log_set_handler_server(wl_log_func_t handler); - #ifdef __cplusplus } #endif +#include "wayland-server-protocol.h" + #endif From ea73cb00bc85e4041e4b9e4d6c460682ad28b69d Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Tue, 28 Apr 2015 22:57:18 +0300 Subject: [PATCH 0140/1152] wayland-egl: add a core header The new core header doesn't include any other header, since it really is not needed. Reviewed-by: Jason Ekstrand Reviewed-by: Pekka Paalanen --- Makefile.am | 1 + src/wayland-egl-core.h | 56 ++++++++++++++++++++++++++++++++++++++++++ src/wayland-egl.h | 29 +--------------------- 3 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 src/wayland-egl-core.h diff --git a/Makefile.am b/Makefile.am index a8a0a56e..5b44d6f2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,7 @@ include_HEADERS = \ src/wayland-client.h \ src/wayland-client-core.h \ src/wayland-egl.h \ + src/wayland-egl-core.h \ src/wayland-version.h nodist_include_HEADERS = \ diff --git a/src/wayland-egl-core.h b/src/wayland-egl-core.h new file mode 100644 index 00000000..c730d9e1 --- /dev/null +++ b/src/wayland-egl-core.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * Copyright © 2011 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef WAYLAND_EGL_CORE_H +#define WAYLAND_EGL_CORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define WL_EGL_PLATFORM 1 + +struct wl_egl_window; +struct wl_surface; + +struct wl_egl_window * +wl_egl_window_create(struct wl_surface *surface, + int width, int height); + +void +wl_egl_window_destroy(struct wl_egl_window *egl_window); + +void +wl_egl_window_resize(struct wl_egl_window *egl_window, + int width, int height, + int dx, int dy); + +void +wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, + int *width, int *height); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland-egl.h b/src/wayland-egl.h index c40280b1..075009f6 100644 --- a/src/wayland-egl.h +++ b/src/wayland-egl.h @@ -24,34 +24,7 @@ #ifndef WAYLAND_EGL_H #define WAYLAND_EGL_H -#ifdef __cplusplus -extern "C" { -#endif - #include - -#define WL_EGL_PLATFORM 1 - -struct wl_egl_window; - -struct wl_egl_window * -wl_egl_window_create(struct wl_surface *surface, - int width, int height); - -void -wl_egl_window_destroy(struct wl_egl_window *egl_window); - -void -wl_egl_window_resize(struct wl_egl_window *egl_window, - int width, int height, - int dx, int dy); - -void -wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, - int *width, int *height); - -#ifdef __cplusplus -} -#endif +#include "wayland-egl-core.h" #endif From e799b1fa9cfd31b541ed5bd184abd1b2e169b61b Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Wed, 29 Apr 2015 16:46:51 +0300 Subject: [PATCH 0141/1152] scanner: add a new --include-core-only option When using this new option the generated code will include the new core headers instead of the old ones. The default needs to remain unchanged for backward compatibility with old code. With this change the generated headers will now forward declare all types and interfaces it uses; that is needed when generating headers for a my-extension.xml with --include-core-only, since it may use types defined in wayland.xml. The same is done also without --include-core-only, since it is an harmless change. getopt_long() is used for the option handling. Reviewed-by: Pekka Paalanen --- src/scanner.c | 246 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 168 insertions(+), 78 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index adc9aa3b..75322f74 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "wayland-util.h" @@ -39,12 +40,17 @@ enum side { static int usage(int ret) { - fprintf(stderr, "usage: ./scanner [client-header|server-header|code]" + fprintf(stderr, "usage: ./scanner [OPTION] [client-header|server-header|code]" " [input_file output_file]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Converts XML protocol descriptions supplied on " "stdin or input file to client\n" - "headers, server headers, or protocol marshalling code.\n"); + "headers, server headers, or protocol marshalling code.\n\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help display this help and exit.\n" + " -c, --include-core-only include the core version of the headers,\n" + " that is e.g. wayland-client-core.h instead\n" + " of wayland-client.h.\n"); exit(ret); } @@ -68,6 +74,7 @@ struct protocol { int null_run_length; char *copyright; struct description *description; + bool core_headers; }; struct interface { @@ -984,65 +991,6 @@ format_copyright(const char *copyright) printf(" */\n\n"); } -static void -emit_header(struct protocol *protocol, enum side side) -{ - struct interface *i; - const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; - - if (protocol->copyright) - format_copyright(protocol->copyright); - - printf("#ifndef %s_%s_PROTOCOL_H\n" - "#define %s_%s_PROTOCOL_H\n" - "\n" - "#ifdef __cplusplus\n" - "extern \"C\" {\n" - "#endif\n" - "\n" - "#include \n" - "#include \n" - "#include \"%s\"\n\n" - "struct wl_client;\n" - "struct wl_resource;\n\n", - protocol->uppercase_name, s, - protocol->uppercase_name, s, - (side == SERVER) ? "wayland-server.h" : "wayland-client.h"); - - wl_list_for_each(i, &protocol->interface_list, link) - printf("struct %s;\n", i->name); - printf("\n"); - - wl_list_for_each(i, &protocol->interface_list, link) { - printf("extern const struct wl_interface " - "%s_interface;\n", - i->name); - } - printf("\n"); - - wl_list_for_each(i, &protocol->interface_list, link) { - - emit_enumerations(i); - - if (side == SERVER) { - emit_structs(&i->request_list, i, side); - emit_opcodes(&i->event_list, i); - emit_opcode_versions(&i->event_list, i); - emit_event_wrappers(&i->event_list, i); - } else { - emit_structs(&i->event_list, i, side); - emit_opcodes(&i->request_list, i); - emit_stubs(&i->request_list, i); - } - } - - printf("#ifdef __cplusplus\n" - "}\n" - "#endif\n" - "\n" - "#endif\n"); -} - static void emit_types_forward_declarations(struct protocol *protocol, struct wl_list *message_list, @@ -1078,6 +1026,106 @@ emit_types_forward_declarations(struct protocol *protocol, } } +static int +cmp_names(const void *p1, const void *p2) +{ + const char * const *s1 = p1, * const *s2 = p2; + + return strcmp(*s1, *s2); +} + +static const char * +get_include_name(bool core, enum side side) +{ + if (side == SERVER) + return core ? "wayland-server-core.h" : "wayland-server.h"; + else + return core ? "wayland-client-core.h" : "wayland-client.h"; +} + +static void +emit_header(struct protocol *protocol, enum side side) +{ + struct interface *i; + struct wl_array types; + const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; + char **p, *prev; + + if (protocol->copyright) + format_copyright(protocol->copyright); + + printf("#ifndef %s_%s_PROTOCOL_H\n" + "#define %s_%s_PROTOCOL_H\n" + "\n" + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n" + "\n" + "#include \n" + "#include \n" + "#include \"%s\"\n\n" + "struct wl_client;\n" + "struct wl_resource;\n\n", + protocol->uppercase_name, s, + protocol->uppercase_name, s, + get_include_name(protocol->core_headers, side)); + + wl_array_init(&types); + wl_list_for_each(i, &protocol->interface_list, link) { + emit_types_forward_declarations(protocol, &i->request_list, &types); + emit_types_forward_declarations(protocol, &i->event_list, &types); + } + + wl_list_for_each(i, &protocol->interface_list, link) { + p = fail_on_null(wl_array_add(&types, sizeof *p)); + *p = i->name; + } + + qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); + prev = NULL; + wl_array_for_each(p, &types) { + if (prev && strcmp(*p, prev) == 0) + continue; + printf("struct %s;\n", *p); + prev = *p; + } + printf("\n"); + + prev = NULL; + wl_array_for_each(p, &types) { + if (prev && strcmp(*p, prev) == 0) + continue; + printf("extern const struct wl_interface " + "%s_interface;\n", *p); + prev = *p; + } + + wl_array_release(&types); + printf("\n"); + + wl_list_for_each(i, &protocol->interface_list, link) { + + emit_enumerations(i); + + if (side == SERVER) { + emit_structs(&i->request_list, i, side); + emit_opcodes(&i->event_list, i); + emit_opcode_versions(&i->event_list, i); + emit_event_wrappers(&i->event_list, i); + } else { + emit_structs(&i->event_list, i, side); + emit_opcodes(&i->request_list, i); + emit_stubs(&i->request_list, i); + } + } + + printf("#ifdef __cplusplus\n" + "}\n" + "#endif\n" + "\n" + "#endif\n"); +} + static void emit_null_run(struct protocol *protocol) { @@ -1181,14 +1229,6 @@ emit_messages(struct wl_list *message_list, printf("};\n\n"); } -static int -cmp_names(const void *p1, const void *p2) -{ - const char * const *s1 = p1, * const *s2 = p2; - - return strcmp(*s1, *s2); -} - static void emit_code(struct protocol *protocol) { @@ -1260,33 +1300,82 @@ int main(int argc, char *argv[]) FILE *input = stdin; int len; void *buf; + bool help = false, core_headers = false; + bool fail = false; + int opt, option_index = 0; enum { CLIENT_HEADER, SERVER_HEADER, CODE, } mode; - if (argc != 2 && argc != 4) - usage(EXIT_FAILURE); - else if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0) + static const struct option options[] = { + {"help", no_argument, 0, 0 }, + {"include-core-only", no_argument, 0, 0 }, + {0, 0, 0, 0 } + }; + + while (1) { + opt = getopt_long(argc, argv, "hc", + options, &option_index); + + if (opt == -1) + break; + + if (opt == 0) { + switch (option_index) { + case 0: + help = true; + break; + case 1: + core_headers = true; + break; + default: + fail = true; + break; + } + continue; + } + + switch (opt) { + case 'h': + help = true; + break; + case 'c': + core_headers = true; + break; + default: + fail = true; + break; + } + } + + argv += optind; + argc -= optind; + + if (help) usage(EXIT_SUCCESS); - else if (strcmp(argv[1], "client-header") == 0) + else if ((argc != 1 && argc != 3) || fail) + usage(EXIT_FAILURE); + else if (strcmp(argv[0], "help") == 0) + usage(EXIT_SUCCESS); + else if (strcmp(argv[0], "client-header") == 0) mode = CLIENT_HEADER; - else if (strcmp(argv[1], "server-header") == 0) + else if (strcmp(argv[0], "server-header") == 0) mode = SERVER_HEADER; - else if (strcmp(argv[1], "code") == 0) + else if (strcmp(argv[0], "code") == 0) mode = CODE; else usage(EXIT_FAILURE); - if (argc == 4) { - input = fopen(argv[2], "r"); + if (argc == 3) { + input = fopen(argv[1], "r"); if (input == NULL) { fprintf(stderr, "Could not open input file: %s\n", strerror(errno)); exit(EXIT_FAILURE); } - if (freopen(argv[3], "w", stdout) == NULL) { + if (freopen(argv[2], "w", stdout) == NULL) { fprintf(stderr, "Could not open output file: %s\n", strerror(errno)); exit(EXIT_FAILURE); @@ -1297,6 +1386,7 @@ int main(int argc, char *argv[]) protocol.type_index = 0; protocol.null_run_length = 0; protocol.copyright = NULL; + protocol.core_headers = core_headers; memset(&ctx, 0, sizeof ctx); ctx.protocol = &protocol; From 8877a349e7b1fe8943962cfcd0dcdf78dc7f39f6 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 6 May 2015 18:59:59 -0700 Subject: [PATCH 0142/1152] configure.ac: bump to version 1.7.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 271eec3e..c1321102 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [7]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From d08c079739caa966350ce9fb8b620f8a69dfb05f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 30 Apr 2015 15:28:35 +0300 Subject: [PATCH 0143/1152] scanner: simplify the getopt logic Use the same retvals for both short and long options. Whitespace fixes. Signed-off-by: Pekka Paalanen --- src/scanner.c | 44 ++++++++++++++------------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 75322f74..58121762 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1302,7 +1302,7 @@ int main(int argc, char *argv[]) void *buf; bool help = false, core_headers = false; bool fail = false; - int opt, option_index = 0; + int opt; enum { CLIENT_HEADER, SERVER_HEADER, @@ -1310,43 +1310,27 @@ int main(int argc, char *argv[]) } mode; static const struct option options[] = { - {"help", no_argument, 0, 0 }, - {"include-core-only", no_argument, 0, 0 }, - {0, 0, 0, 0 } + { "help", no_argument, NULL, 'h' }, + { "include-core-only", no_argument, NULL, 'c' }, + { 0, 0, NULL, 0 } }; while (1) { - opt = getopt_long(argc, argv, "hc", - options, &option_index); + opt = getopt_long(argc, argv, "hc", options, NULL); if (opt == -1) break; - if (opt == 0) { - switch (option_index) { - case 0: - help = true; - break; - case 1: - core_headers = true; - break; - default: - fail = true; - break; - } - continue; - } - switch (opt) { - case 'h': - help = true; - break; - case 'c': - core_headers = true; - break; - default: - fail = true; - break; + case 'h': + help = true; + break; + case 'c': + core_headers = true; + break; + default: + fail = true; + break; } } From b409c919a28ffe9f72ec15156d91af0ab17a196e Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Fri, 15 May 2015 17:12:41 +0200 Subject: [PATCH 0144/1152] remove trailing whitespaces Remove trailing whitespaces because they are not needed and jumping to the end of al ine should do just that and not jump to the whitespace. --- cursor/cursor-data.h | 1004 +++++++++++++++++++------------------- src/scanner.c | 2 +- tests/connection-test.c | 8 +- tests/list-test.c | 2 +- tests/os-wrappers-test.c | 2 +- 5 files changed, 509 insertions(+), 509 deletions(-) diff --git a/cursor/cursor-data.h b/cursor/cursor-data.h index 4c5e6723..b1026d73 100644 --- a/cursor/cursor-data.h +++ b/cursor/cursor-data.h @@ -22,508 +22,508 @@ */ static uint32_t cursor_data[] = { - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, - 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0xff000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, - 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, - 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, + 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, + 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0xff000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, + 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, }; static struct cursor_metadata { diff --git a/src/scanner.c b/src/scanner.c index 58121762..11efffcf 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -365,7 +365,7 @@ start_element(void *data, const char *element_name, const char **atts) ctx->protocol->uppercase_name = uppercase_dup(name); ctx->protocol->description = NULL; } else if (strcmp(element_name, "copyright") == 0) { - + } else if (strcmp(element_name, "interface") == 0) { if (name == NULL) fail(&ctx->loc, "no interface name given"); diff --git a/tests/connection-test.c b/tests/connection-test.c index d34e9a50..7947f08f 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -223,7 +223,7 @@ expected_fail_marshal(int expected_error, const char *format, ...) { struct wl_closure *closure; static const uint32_t opcode = 4444; - static const struct wl_interface test_interface = { + static const struct wl_interface test_interface = { .name = "test_object" }; static struct wl_object sender = { 0 }; @@ -412,13 +412,13 @@ TEST(connection_demarshal) msg[0] = 400200; msg[1] = 12; msg[2] = 0; - demarshal(&data, "?s", msg, (void *) validate_demarshal_s); + demarshal(&data, "?s", msg, (void *) validate_demarshal_s); release_marshal_data(&data); } static void -marshal_demarshal(struct marshal_data *data, +marshal_demarshal(struct marshal_data *data, void (*func)(void), int size, const char *format, ...) { struct wl_closure *closure; @@ -501,7 +501,7 @@ TEST(connection_marshal_alot) int i; setup_marshal_data(&data); - + /* We iterate enough to make sure we wrap the circular buffers * for both regular data an fds. */ diff --git a/tests/list-test.c b/tests/list-test.c index 6058fe3b..dfe09aca 100644 --- a/tests/list-test.c +++ b/tests/list-test.c @@ -103,7 +103,7 @@ validate_list(struct wl_list *list, int *reference, int length) return 0; i++; } - + if (i != length) return 0; diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index e5cdac44..edc096c3 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -225,7 +225,7 @@ setup_marshal_data(struct marshal_data *data) } static void -marshal_demarshal(struct marshal_data *data, +marshal_demarshal(struct marshal_data *data, void (*func)(void), int size, const char *format, ...) { struct wl_closure *closure; From 12cab2c4dfd4634e8979f78cec855a14091ce9d9 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 15 May 2015 17:53:29 -0700 Subject: [PATCH 0145/1152] configure.ac: bump to version 1.7.92 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c1321102..0d834fba 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [7]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 1fab2e7ba95a548129abf117f66e21c5a633091a Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Thu, 21 May 2015 20:43:13 +0300 Subject: [PATCH 0146/1152] tests: add an headers test This test checks that the protocol and library headers include only what they are supposed to include. That is, that the core headers do not include the protocol headers and that the core protocol headers do not include the non core library headers. The build process now generates core protocol headers, but they are only used in the test and don't get installed. Reviewed-by: Bryce Harrington --- Makefile.am | 19 ++++++++++-- tests/headers-protocol-core-test.c | 31 ++++++++++++++++++ tests/headers-protocol-test.c | 31 ++++++++++++++++++ tests/headers-test.c | 50 ++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 tests/headers-protocol-core-test.c create mode 100644 tests/headers-protocol-test.c create mode 100644 tests/headers-test.c diff --git a/Makefile.am b/Makefile.am index 5b44d6f2..c19494ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,9 +85,16 @@ protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@ +protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header -c < $< > $@ + +protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header -c < $< > $@ + BUILT_SOURCES = \ $(nodist_libwayland_server_la_SOURCES) \ - $(nodist_libwayland_client_la_SOURCES) + $(nodist_libwayland_client_la_SOURCES) \ + $(nodist_headers_test_SOURCES) CLEANFILES = $(BUILT_SOURCES) DISTCLEANFILES = src/wayland-version.h @@ -132,7 +139,8 @@ TESTS = \ queue-test \ signal-test \ resources-test \ - message-test + message-test \ + headers-test if ENABLE_CPP_TEST TESTS += cpp-compile-test @@ -188,6 +196,13 @@ resources_test_SOURCES = tests/resources-test.c resources_test_LDADD = libtest-runner.la message_test_SOURCES = tests/message-test.c message_test_LDADD = libtest-runner.la +headers_test_SOURCES = tests/headers-test.c \ + tests/headers-protocol-test.c \ + tests/headers-protocol-core-test.c +headers_test_LDADD = libtest-runner.la +nodist_headers_test_SOURCES = \ + protocol/wayland-server-protocol-core.h \ + protocol/wayland-client-protocol-core.h if ENABLE_CPP_TEST cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp diff --git a/tests/headers-protocol-core-test.c b/tests/headers-protocol-core-test.c new file mode 100644 index 00000000..60a8a624 --- /dev/null +++ b/tests/headers-protocol-core-test.c @@ -0,0 +1,31 @@ +/* + * Copyright © 2015 Giulio Camuffo + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "wayland-client-protocol-core.h" +#include "wayland-server-protocol-core.h" + +#ifdef WAYLAND_CLIENT_H +#error including wayland-client-protocol-core.h included wayland-client.h! +#endif +#ifdef WAYLAND_SERVER_H +#error including wayland-server-protocol-core.h included wayland-server.h! +#endif diff --git a/tests/headers-protocol-test.c b/tests/headers-protocol-test.c new file mode 100644 index 00000000..f8726bae --- /dev/null +++ b/tests/headers-protocol-test.c @@ -0,0 +1,31 @@ +/* + * Copyright © 2015 Giulio Camuffo + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "wayland-client-protocol.h" +#include "wayland-server-protocol.h" + +#ifndef WAYLAND_CLIENT_H +#error including wayland-client-protocol.h did not include wayland-client.h! +#endif +#ifndef WAYLAND_SERVER_H +#error including wayland-server-protocol.h did not include wayland-server.h! +#endif diff --git a/tests/headers-test.c b/tests/headers-test.c new file mode 100644 index 00000000..6dc38782 --- /dev/null +++ b/tests/headers-test.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2015 Giulio Camuffo + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "wayland-client-core.h" +#include "wayland-server-core.h" + +#ifdef WL_DISPLAY_SYNC +#error including wayland-client-core.h imported protocol symbols! +#endif +#ifdef WL_DISPLAY_ERROR +#error including wayland-server-core.h imported protocol symbols! +#endif + +#ifdef WAYLAND_CLIENT_H +#error including wayland-client-core.h included the non-core header! +#endif +#ifdef WAYLAND_SERVER_H +#error including wayland-server-core.h included the non-core header! +#endif + +#include "wayland-client.h" +#include "wayland-server.h" + +#ifndef WL_DISPLAY_SYNC +#error including wayland-client.h did not import protocol symbols! +#endif +#ifndef WL_DISPLAY_ERROR +#error including wayland-server.h did not import protocol symbols! +#endif + +int main(int argc, char **argv) { return 0; } From 5339e21f65201898d7058fd7d50414abb7ba51b4 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 26 May 2015 18:59:25 -0700 Subject: [PATCH 0147/1152] gitignore: ignore recently added headers-test --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index defe6251..0f59395a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ event-loop-test exec-fd-leak-checker fixed-benchmark fixed-test +headers-test list-test map-test message-test From 8e8699789c32d2f574c3afe0b0f4c37353b73e29 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 26 May 2015 19:01:00 -0700 Subject: [PATCH 0148/1152] gitignore: Bulk ignore all *-test files --- .gitignore | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 0f59395a..a59564a1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.trs *.tar.xz *~ +*-test .libs .dirstamp cscope.out @@ -37,24 +38,7 @@ ctags /test-driver Makefile Makefile.in -array-test -client-test -connection-test -cpp-compile-test -display-test -event-loop-test exec-fd-leak-checker fixed-benchmark -fixed-test -headers-test -list-test -map-test -message-test -os-wrappers-test -queue-test -resources-test -sanity-test -signal-test -socket-test /wayland-scanner protocol/*.[ch] From 6ffd998a98ca76ff2ff64617516fe1d6d34100a3 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 26 May 2015 19:10:15 -0700 Subject: [PATCH 0149/1152] configure.ac: bump to version 1.7.93 for the RC2 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0d834fba..d3346164 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [7]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From c19d5e1867ef179f118f164a3457cb5366cf4055 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 27 May 2015 15:34:20 -0700 Subject: [PATCH 0150/1152] publish-doc: Add script for publishing docs to the website Adapted from same-named script from libinput. --- publish-doc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 publish-doc diff --git a/publish-doc b/publish-doc new file mode 100755 index 00000000..80fc22a0 --- /dev/null +++ b/publish-doc @@ -0,0 +1,15 @@ +#!/bin/bash + +set -e + +[ -e doc ] || (echo "Run this from the project root" && exit 1) + +make + +DOC_HTML=./doc/publican/Wayland/en-US/html/ + +[ -e "${DOC_HTML}" ] || (echo "HTML documentation failed to build at ${DOC_HTML}" && exit 1) + +chmod -R g+x ${DOC_HTML} + +rsync --delete -avz ${DOC_HTML} freedesktop.org:/srv/wayland.freedesktop.org/www/docs/html/ From f0be757bfaf8cd43e89471ec7fa8f57093d38f81 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Thu, 28 May 2015 19:30:33 +0300 Subject: [PATCH 0151/1152] scanner: don't emit the extern declarations for external types We were emitting the extern declarations of all types used in the protocol, even if not defined in it. This caused warnings to be produced when using the -Wredundant-decls compiler flag when building an extension that uses e.g. wl_surface. However we only need the extern declarations if the protocol defines a factory for those external interfaces. That is a bad design and can be however done by including the dependent protocol header first. So only emit the extern declarations for the types that the protocol actually defines, this restoring the behavior we were using in 1.7. Fixes https://bugs.freedesktop.org/show_bug.cgi?id=90677 Reviewed-by: Pekka Paalanen Tested-by: Arnaud Vrac --- src/scanner.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 11efffcf..4ab7d855 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1089,18 +1089,14 @@ emit_header(struct protocol *protocol, enum side side) printf("struct %s;\n", *p); prev = *p; } + wl_array_release(&types); printf("\n"); - prev = NULL; - wl_array_for_each(p, &types) { - if (prev && strcmp(*p, prev) == 0) - continue; + wl_list_for_each(i, &protocol->interface_list, link) { printf("extern const struct wl_interface " - "%s_interface;\n", *p); - prev = *p; + "%s_interface;\n", i->name); } - wl_array_release(&types); printf("\n"); wl_list_for_each(i, &protocol->interface_list, link) { From 60024af597b68974c451c89f960a7c11de11c33a Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 2 Jun 2015 16:06:02 -0700 Subject: [PATCH 0152/1152] configure.ac: bump to version 1.8.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d3346164..e9fcf51d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [7]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [8]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From baed4b0a2ffd6f61e0f868af7013cd24dd4b429c Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 3 Jun 2015 00:12:49 -0700 Subject: [PATCH 0153/1152] configure.ac: bump version to 1.8.90 Master is open for new features again Signed-off-by: Bryce Harrington --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e9fcf51d..952f231d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [8]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 56a5a890b5d663a2157551ed5974b9dc929749ae Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 28 May 2015 10:19:09 -0500 Subject: [PATCH 0154/1152] docs: remove and ignore doc/doxygen_sqlite3.db Some newer versions of doxygen are generating this file now, and if we don't clean it up distcheck will fail. Known to affect doxygen 1.8.8 from debian jessie. Signed-off-by: Derek Foreman Reviewed-by: Jon A. Cruz Tested-by: Jon A. Cruz --- Makefile.am | 2 +- doc/doxygen/.gitignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index c19494ff..0ea300a1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,7 +96,7 @@ BUILT_SOURCES = \ $(nodist_libwayland_client_la_SOURCES) \ $(nodist_headers_test_SOURCES) -CLEANFILES = $(BUILT_SOURCES) +CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db DISTCLEANFILES = src/wayland-version.h EXTRA_DIST = src/wayland-version.h.in diff --git a/doc/doxygen/.gitignore b/doc/doxygen/.gitignore index 5f825986..730a1ef0 100644 --- a/doc/doxygen/.gitignore +++ b/doc/doxygen/.gitignore @@ -1,2 +1,3 @@ +doxygen_sqlite3.db wayland.doxygen xml/ From c4bad43425c32a9b5f1f83987a5ac05c971896ca Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 9 Jun 2015 16:43:47 -0700 Subject: [PATCH 0155/1152] COPYING: Update to MIT Expat License rather than MIT X License MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIT has released software under several slightly different licenses, including the old 'X11 License' or 'MIT License'. Some code under this license was in fact included in X.org's Xserver in the past. However, X.org now prefers the MIT Expat License as the standard (which, confusingly, is also referred to as the 'MIT License'). See http://cgit.freedesktop.org/xorg/xserver/tree/COPYING When Wayland started, it was Kristian Høgsberg's intent to license it compatibly with X.org. "I wanted Wayland to be usable (license-wise) whereever X was usable." But, the text of the older X11 License was taken for Wayland, rather than X11's current standard. This patch corrects this by swapping in the intended text. In practical terms, the most notable change is the dropping of the no-advertising clause. Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- COPYING | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/COPYING b/COPYING index 6ba3d981..eb25a4e2 100644 --- a/COPYING +++ b/COPYING @@ -3,20 +3,27 @@ Copyright © 2010-2012 Intel Corporation Copyright © 2011 Benjamin Franzke Copyright © 2012 Collabora, Ltd. -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that copyright -notice and this permission notice appear in supporting documentation, and -that the name of the copyright holders not be used in advertising or -publicity pertaining to distribution of the software without specific, -written prior permission. The copyright holders make no representations -about the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: -THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO -EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR -CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -OF THIS SOFTWARE. +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +--- + +The above is the version of the MIT "Expat" License used by X.org: + + http://cgit.freedesktop.org/xorg/xserver/tree/COPYING From 2e6e0fc811ed0207b1d2c3d3ebfc95010189dfa2 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 11:48:53 -0700 Subject: [PATCH 0156/1152] Contributing: Specify use of MIT Expat for new code files Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- doc/Contributing | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/Contributing b/doc/Contributing index c51b7e80..39c3e394 100644 --- a/doc/Contributing +++ b/doc/Contributing @@ -75,6 +75,19 @@ my_function(void) x = function_with_a_really_long_name(parameter1, parameter2, parameter3, parameter4); +== Licensing == + +Wayland is licensed with the intention to be usable anywhere X.org is. +Originally, X.org was covered under the MIT X11 license, but changed to +the MIT Expat license. Similarly, Wayland was covered initially as MIT +X11 licensed, but changed to the MIT Expat license, following in X.org's +footsteps. Other than wording, the two licenses are substantially the +same, with the exeption of a no-advertising clause in X11 not included +in Expat. + +New source code files should specify the MIT Expat license in their +boilerplate, as part of the copyright statement. + == References == [1] http://git-scm.com/documentation From 773babedfca8f0aa60903aed4a6856cd7e36227d Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 02:57:59 -0700 Subject: [PATCH 0157/1152] tests: Update boilerplate from MIT X11 license to MIT Expat license Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- tests/array-test.c | 35 ++++++++++++++++-------------- tests/client-test.c | 35 ++++++++++++++++-------------- tests/connection-test.c | 35 ++++++++++++++++-------------- tests/display-test.c | 35 ++++++++++++++++-------------- tests/event-loop-test.c | 35 ++++++++++++++++-------------- tests/exec-fd-leak-checker.c | 35 ++++++++++++++++-------------- tests/fixed-benchmark.c | 35 ++++++++++++++++-------------- tests/fixed-test.c | 35 ++++++++++++++++-------------- tests/headers-protocol-core-test.c | 35 ++++++++++++++++-------------- tests/headers-protocol-test.c | 35 ++++++++++++++++-------------- tests/headers-test.c | 35 ++++++++++++++++-------------- tests/list-test.c | 35 ++++++++++++++++-------------- tests/map-test.c | 35 ++++++++++++++++-------------- tests/message-test.c | 35 ++++++++++++++++-------------- tests/os-wrappers-test.c | 35 ++++++++++++++++-------------- tests/queue-test.c | 35 ++++++++++++++++-------------- tests/resources-test.c | 35 ++++++++++++++++-------------- tests/sanity-test.c | 35 ++++++++++++++++-------------- tests/signal-test.c | 35 ++++++++++++++++-------------- tests/socket-test.c | 35 ++++++++++++++++-------------- tests/test-compositor.c | 35 ++++++++++++++++-------------- tests/test-compositor.h | 35 ++++++++++++++++-------------- tests/test-helpers.c | 35 ++++++++++++++++-------------- tests/test-runner.c | 35 ++++++++++++++++-------------- 24 files changed, 456 insertions(+), 384 deletions(-) diff --git a/tests/array-test.c b/tests/array-test.c index c457e422..37b9afd5 100644 --- a/tests/array-test.c +++ b/tests/array-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/client-test.c b/tests/client-test.c index fde38778..2e332f81 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/connection-test.c b/tests/connection-test.c index 7947f08f..e9832b75 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/display-test.c b/tests/display-test.c index 0f862157..161a4028 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -2,23 +2,26 @@ * Copyright © 2012 Intel Corporation * Copyright © 2013 Jason Ekstrand * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index 1a45db1f..ae5ff945 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -2,23 +2,26 @@ * Copyright © 2012 Intel Corporation * Copyright © 2012 Jason Ekstrand * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/exec-fd-leak-checker.c b/tests/exec-fd-leak-checker.c index 66209ad5..0c69da3a 100644 --- a/tests/exec-fd-leak-checker.c +++ b/tests/exec-fd-leak-checker.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/fixed-benchmark.c b/tests/fixed-benchmark.c index 07190637..8d73c83f 100644 --- a/tests/fixed-benchmark.c +++ b/tests/fixed-benchmark.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/fixed-test.c b/tests/fixed-test.c index 739a3b1b..47a4dae8 100644 --- a/tests/fixed-test.c +++ b/tests/fixed-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/headers-protocol-core-test.c b/tests/headers-protocol-core-test.c index 60a8a624..aabcb0b3 100644 --- a/tests/headers-protocol-core-test.c +++ b/tests/headers-protocol-core-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2015 Giulio Camuffo * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "wayland-client-protocol-core.h" diff --git a/tests/headers-protocol-test.c b/tests/headers-protocol-test.c index f8726bae..87952f7e 100644 --- a/tests/headers-protocol-test.c +++ b/tests/headers-protocol-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2015 Giulio Camuffo * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "wayland-client-protocol.h" diff --git a/tests/headers-test.c b/tests/headers-test.c index 6dc38782..51856f82 100644 --- a/tests/headers-test.c +++ b/tests/headers-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2015 Giulio Camuffo * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "wayland-client-core.h" diff --git a/tests/list-test.c b/tests/list-test.c index dfe09aca..21ca4ecb 100644 --- a/tests/list-test.c +++ b/tests/list-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/map-test.c b/tests/map-test.c index 3df374c8..d2590488 100644 --- a/tests/map-test.c +++ b/tests/map-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/message-test.c b/tests/message-test.c index b5b00a46..cb08f90c 100644 --- a/tests/message-test.c +++ b/tests/message-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2014 Jonas Ådahl * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index edc096c3..b636b622 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -2,23 +2,26 @@ * Copyright © 2012 Collabora, Ltd. * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE diff --git a/tests/queue-test.c b/tests/queue-test.c index 9eb913c0..dc1a01db 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Jonas Ådahl * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/resources-test.c b/tests/resources-test.c index a6ce3ae1..ea88afbb 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2013 Marek Chalupa * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/sanity-test.c b/tests/sanity-test.c index b5a6fae3..3f589b56 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/signal-test.c b/tests/signal-test.c index db83abc2..7bbaa9fc 100644 --- a/tests/signal-test.c +++ b/tests/signal-test.c @@ -1,23 +1,26 @@ /* * Copyright © 2013 Marek Chalupa * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/socket-test.c b/tests/socket-test.c index 4a2272c5..512cf9ad 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -1,21 +1,24 @@ /* - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 1caea18c..296db3bb 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -1,23 +1,26 @@ /* * Copyright (c) 2014 Red Hat, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/test-compositor.h b/tests/test-compositor.h index c41b17b8..c97eb96d 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -1,23 +1,26 @@ /* * Copyright (c) 2014 Red Hat, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/test-helpers.c b/tests/test-helpers.c index c05f4b1c..a9900036 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/tests/test-runner.c b/tests/test-runner.c index 1e5f5878..742b4f0b 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE From 724b6e4ebedd6dae84edff1f13d4ef8a759257fe Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 03:00:28 -0700 Subject: [PATCH 0158/1152] socket-test: Fix style on multi-line comment Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- tests/socket-test.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/socket-test.c b/tests/socket-test.c index 512cf9ad..c53f972e 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -34,8 +34,9 @@ #include "test-runner.h" /* Paths longer than what the .sun_path array can contain must be rejected. - This is a hard limitation of assigning a name to AF_UNIX/AF_LOCAL sockets. - See `man 7 unix`. */ + * This is a hard limitation of assigning a name to AF_UNIX/AF_LOCAL sockets. + * See `man 7 unix`. + */ static const struct sockaddr_un example_sockaddr_un; From d21ba735eebc1dabf347a302c1aaaefff87c43ef Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 03:15:36 -0700 Subject: [PATCH 0159/1152] test-runner: Add copyright boilerplate for .h, same as the .c Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- tests/test-runner.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test-runner.h b/tests/test-runner.h index 6054da56..64f8d4c6 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -1,3 +1,27 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #ifndef _TEST_RUNNER_H_ #define _TEST_RUNNER_H_ From 3c91b0878def1a42c6d0090fa0b5a47df6092d7c Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 10:54:15 -0700 Subject: [PATCH 0160/1152] src: Update boilerplate from MIT X11 license to MIT Expat license Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- src/connection.c | 35 +++++++++++++++++++---------------- src/event-loop.c | 35 +++++++++++++++++++---------------- src/scanner.c | 35 +++++++++++++++++++---------------- src/wayland-client-core.h | 35 +++++++++++++++++++---------------- src/wayland-client.c | 35 +++++++++++++++++++---------------- src/wayland-client.h | 35 +++++++++++++++++++---------------- src/wayland-egl-core.h | 35 +++++++++++++++++++---------------- src/wayland-egl.h | 35 +++++++++++++++++++---------------- src/wayland-os.c | 35 +++++++++++++++++++---------------- src/wayland-os.h | 35 +++++++++++++++++++---------------- src/wayland-private.h | 35 +++++++++++++++++++---------------- src/wayland-server-core.h | 35 +++++++++++++++++++---------------- src/wayland-server.c | 35 +++++++++++++++++++---------------- src/wayland-server.h | 35 +++++++++++++++++++---------------- src/wayland-shm.c | 35 +++++++++++++++++++---------------- src/wayland-util.c | 35 +++++++++++++++++++---------------- src/wayland-util.h | 35 +++++++++++++++++++---------------- src/wayland-version.h.in | 35 +++++++++++++++++++---------------- 18 files changed, 342 insertions(+), 288 deletions(-) diff --git a/src/connection.c b/src/connection.c index 25451948..b3d9bd45 100644 --- a/src/connection.c +++ b/src/connection.c @@ -2,23 +2,26 @@ * Copyright © 2008 Kristian Høgsberg * Copyright © 2013 Jason Ekstrand * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE diff --git a/src/event-loop.c b/src/event-loop.c index d257d78c..d1e03fae 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/src/scanner.c b/src/scanner.c index 4ab7d855..7d8cfb91 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -2,23 +2,26 @@ * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index d7a0d9ed..dea70d9c 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_CLIENT_CORE_H diff --git a/src/wayland-client.c b/src/wayland-client.c index ed108e1f..6450b67d 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2,23 +2,26 @@ * Copyright © 2008-2012 Kristian Høgsberg * Copyright © 2010-2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE diff --git a/src/wayland-client.h b/src/wayland-client.h index 37b0d7f2..38565357 100644 --- a/src/wayland-client.h +++ b/src/wayland-client.h @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ diff --git a/src/wayland-egl-core.h b/src/wayland-egl-core.h index c730d9e1..b3ab5124 100644 --- a/src/wayland-egl-core.h +++ b/src/wayland-egl-core.h @@ -2,23 +2,26 @@ * Copyright © 2011 Kristian Høgsberg * Copyright © 2011 Benjamin Franzke * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_EGL_CORE_H diff --git a/src/wayland-egl.h b/src/wayland-egl.h index 075009f6..279dcb8b 100644 --- a/src/wayland-egl.h +++ b/src/wayland-egl.h @@ -2,23 +2,26 @@ * Copyright © 2011 Kristian Høgsberg * Copyright © 2011 Benjamin Franzke * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_EGL_H diff --git a/src/wayland-os.c b/src/wayland-os.c index 1185e1db..93b6f5fc 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE diff --git a/src/wayland-os.h b/src/wayland-os.h index c612975d..f51efaa6 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_OS_H diff --git a/src/wayland-private.h b/src/wayland-private.h index db76081c..17c507cd 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -3,23 +3,26 @@ * Copyright © 2011 Intel Corporation * Copyright © 2013 Jason Ekstrand * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_PRIVATE_H diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 7d037892..e605432c 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_SERVER_CORE_H diff --git a/src/wayland-server.c b/src/wayland-server.c index ecbae683..3dc50487 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE diff --git a/src/wayland-server.h b/src/wayland-server.h index 9fe19f50..b6d0e2bc 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ diff --git a/src/wayland-shm.c b/src/wayland-shm.c index b6b31d6f..5c419fac 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. * * Authors: * Kristian Høgsberg diff --git a/src/wayland-util.c b/src/wayland-util.c index db51ebb1..00265e9f 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -2,23 +2,26 @@ * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include diff --git a/src/wayland-util.h b/src/wayland-util.h index 2bc3ff5a..3d04bdd0 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -1,23 +1,26 @@ /* * Copyright © 2008 Kristian Høgsberg * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ /** \file wayland-util.h diff --git a/src/wayland-version.h.in b/src/wayland-version.h.in index 9a746caf..c5d786e2 100644 --- a/src/wayland-version.h.in +++ b/src/wayland-version.h.in @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_VERSION_H From 68402a53dc6ab9eeb15644a4ad66af2c0af2191d Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 11:26:29 -0700 Subject: [PATCH 0161/1152] wayland-server: Fix style on multi-line comment Signed-off-by: Bryce Harrington --- src/wayland-server.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 3dc50487..0f04f661 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -50,8 +50,9 @@ #include "wayland-os.h" /* This is the size of the char array in struct sock_addr_un. - No Wayland socket can be created with a path longer than this, - including the null terminator. */ + * No Wayland socket can be created with a path longer than this, + * including the null terminator. + */ #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif From 541b0cf24effa2705e9ea8ae2f3d89272c27bb89 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 10:58:50 -0700 Subject: [PATCH 0162/1152] protocol: Update boilerplate from MIT X11 license to MIT Expat license Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f52677f8..42c93090 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -6,26 +6,26 @@ Copyright © 2010-2011 Intel Corporation Copyright © 2012-2013 Collabora, Ltd. - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. From 3540ea2b9fc3c2f244cf62d82b7d31d4223044c9 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 11:03:00 -0700 Subject: [PATCH 0163/1152] cursor: Update boilerplate from MIT X11 license to MIT Expat license Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- cursor/convert_font.c | 35 +++++++++++++++++++---------------- cursor/os-compatibility.c | 35 +++++++++++++++++++---------------- cursor/os-compatibility.h | 35 +++++++++++++++++++---------------- cursor/wayland-cursor.c | 35 +++++++++++++++++++---------------- cursor/wayland-cursor.h | 35 +++++++++++++++++++---------------- 5 files changed, 95 insertions(+), 80 deletions(-) diff --git a/cursor/convert_font.c b/cursor/convert_font.c index de1b8ad5..df40ca32 100644 --- a/cursor/convert_font.c +++ b/cursor/convert_font.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Philipp Brüschweiler * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ /* diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 0c412428..d7d4b33b 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define _GNU_SOURCE diff --git a/cursor/os-compatibility.h b/cursor/os-compatibility.h index 947555c5..d0e69acd 100644 --- a/cursor/os-compatibility.h +++ b/cursor/os-compatibility.h @@ -1,23 +1,26 @@ /* * Copyright © 2012 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef OS_COMPATIBILITY_H diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 410a0d40..18abe87a 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "config.h" diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h index c3884a04..09a13a7b 100644 --- a/cursor/wayland-cursor.h +++ b/cursor/wayland-cursor.h @@ -1,23 +1,26 @@ /* * Copyright © 2012 Intel Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef WAYLAND_CURSOR_H From c78a0a62c6246ed9398a7f277cac02d3d55bc6f0 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 11:27:29 -0700 Subject: [PATCH 0164/1152] cursor-data.h: Change SuSE licensed code from X11 to Expat The license text for this file mentions SuSE specifically, however it is otherwise identical to all the other MIT X11 licensed code in Wayland, and so can be changed to the substantially identical MIT Expat license. Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen Acked-by: Keith Packard --- cursor/cursor-data.h | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/cursor/cursor-data.h b/cursor/cursor-data.h index b1026d73..0d03cd53 100644 --- a/cursor/cursor-data.h +++ b/cursor/cursor-data.h @@ -1,22 +1,26 @@ /* * Copyright 1999 SuSE, Inc. * -* Permission to use, copy, modify, distribute, and sell this software and its -* documentation for any purpose is hereby granted without fee, provided that -* the above copyright notice appear in all copies and that both that -* copyright notice and this permission notice appear in supporting -* documentation, and that the name of SuSE not be used in advertising or -* publicity pertaining to distribution of the software without specific, -* written prior permission. SuSE makes no representations about the -* suitability of this software for any purpose. It is provided "as is" -* without express or implied warranty. +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: * -* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE -* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. * * Author: Keith Packard, SuSE, Inc. */ From 1faeb7ff4894be9649d042103178ce22693cd6d1 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 10 Jun 2015 11:36:21 -0700 Subject: [PATCH 0165/1152] xcursor: Change keithp licensed code from X11 to Expat license The license text for this file mentions Keith Packard specifically, however it is otherwise identical to all the other MIT X11 licensed code in Wayland, and so can be changed to the substantially identical MIT Expat license. Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen Acked-by: Keith Packard --- cursor/xcursor.c | 35 +++++++++++++++++++---------------- cursor/xcursor.h | 35 +++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index f9d9669b..ca41c4ac 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -1,23 +1,26 @@ /* * Copyright © 2002 Keith Packard * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "xcursor.h" diff --git a/cursor/xcursor.h b/cursor/xcursor.h index f518767a..62e23220 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -1,23 +1,26 @@ /* * Copyright © 2002 Keith Packard * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef XCURSOR_H From e06f88cf91384099a45ca5e194bbb12d499b1ff9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 17 Jun 2015 15:13:48 -0500 Subject: [PATCH 0166/1152] build: Move AM_CFLAGS and AM_CPPFLAGS to the top of Makefile.am AM_CFLAGS and AM_CPPFLAGS aren't positional, so putting them at a random place in Makefile.am can be misleading. Signed-off-by: Derek Foreman Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- Makefile.am | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0ea300a1..96ad0be8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,13 @@ endif ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} +AM_CPPFLAGS = \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/protocol + +AM_CFLAGS = $(GCC_CFLAGS) $(FFI_CFLAGS) + aclocaldir = $(datadir)/aclocal dist_aclocal_DATA = wayland-scanner.m4 @@ -214,12 +221,5 @@ fixed_benchmark_LDADD = libtest-runner.la os_wrappers_test_SOURCES = tests/os-wrappers-test.c os_wrappers_test_LDADD = libtest-runner.la -AM_CPPFLAGS = \ - -I$(top_builddir)/src \ - -I$(top_srcdir)/src \ - -I$(top_builddir)/protocol - -AM_CFLAGS = $(GCC_CFLAGS) $(FFI_CFLAGS) - exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la From aeeca3169663336a7719faad36a11e0716bd381b Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 17 Jun 2015 15:13:49 -0500 Subject: [PATCH 0167/1152] build: Stop putting FFI_CFLAGS in AM_CFLAGS AM_CFLAGS are the defaults passed to anything that doesn't specify its own _CFLAGS, so instead of putting FFI_CFLAGS there, let's just add that to anything that actually needs it. The only thing that needs it but didn't have it specifically was libwayland_util (for connection.c) Signed-off-by: Derek Foreman Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 96ad0be8..34f8473f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_builddir)/protocol -AM_CFLAGS = $(GCC_CFLAGS) $(FFI_CFLAGS) +AM_CFLAGS = $(GCC_CFLAGS) aclocaldir = $(datadir)/aclocal dist_aclocal_DATA = wayland-scanner.m4 @@ -39,6 +39,7 @@ nodist_include_HEADERS = \ protocol/wayland-server-protocol.h \ protocol/wayland-client-protocol.h +libwayland_util_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) libwayland_util_la_SOURCES = \ src/connection.c \ src/wayland-util.c \ From 5cfdbef3d29919ef37cfe309ff907763d849febf Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 17 Jun 2015 15:13:50 -0500 Subject: [PATCH 0168/1152] build: Allow disabling building of wayland libraries When cross-compiling it may be useful to build only the wayland-scanner natively. This patch makes it possible to disable build of the libraries. Signed-off-by: Derek Foreman Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- Makefile.am | 47 +++++++++++++++++++++++++---------------------- configure.ac | 30 ++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Makefile.am b/Makefile.am index 34f8473f..31adc973 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,9 +22,32 @@ dist_pkgdata_DATA = \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = -lib_LTLIBRARIES = libwayland-server.la libwayland-client.la +if ENABLE_SCANNER +wayland_scanner = $(top_builddir)/wayland-scanner +bin_PROGRAMS = wayland-scanner +wayland_scanner_SOURCES = src/scanner.c +wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS) +wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la +$(BUILT_SOURCES) : wayland-scanner +pkgconfig_DATA += src/wayland-scanner.pc +else +wayland_scanner = wayland-scanner +endif + +libwayland_util_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) +libwayland_util_la_SOURCES = \ + src/connection.c \ + src/wayland-util.c \ + src/wayland-util.h \ + src/wayland-os.c \ + src/wayland-os.h \ + src/wayland-private.h + noinst_LTLIBRARIES = libwayland-util.la +if ENABLE_LIBRARIES +lib_LTLIBRARIES = libwayland-server.la libwayland-client.la + include_HEADERS = \ src/wayland-util.h \ src/wayland-server.h \ @@ -39,15 +62,6 @@ nodist_include_HEADERS = \ protocol/wayland-server-protocol.h \ protocol/wayland-client-protocol.h -libwayland_util_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -libwayland_util_la_SOURCES = \ - src/connection.c \ - src/wayland-util.c \ - src/wayland-util.h \ - src/wayland-os.c \ - src/wayland-os.h \ - src/wayland-private.h - libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -pthread libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm libwayland_server_la_LDFLAGS = -version-info 1:0:1 @@ -72,18 +86,6 @@ nodist_libwayland_client_la_SOURCES = \ pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc -if ENABLE_SCANNER -wayland_scanner = $(top_builddir)/wayland-scanner -bin_PROGRAMS = wayland-scanner -wayland_scanner_SOURCES = src/scanner.c -wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS) -wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la -$(BUILT_SOURCES) : wayland-scanner -pkgconfig_DATA += src/wayland-scanner.pc -else -wayland_scanner = wayland-scanner -endif - protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@ @@ -224,3 +226,4 @@ os_wrappers_test_LDADD = libtest-runner.la exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la +endif diff --git a/configure.ac b/configure.ac index 952f231d..39e31072 100644 --- a/configure.ac +++ b/configure.ac @@ -54,16 +54,11 @@ AC_SUBST(GCC_CFLAGS) AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate]) -AC_CHECK_DECL(SFD_CLOEXEC,[], - [AC_MSG_ERROR("SFD_CLOEXEC is needed to compile wayland")], - [[#include ]]) -AC_CHECK_DECL(TFD_CLOEXEC,[], - [AC_MSG_ERROR("TFD_CLOEXEC is needed to compile wayland")], - [[#include ]]) -AC_CHECK_DECL(CLOCK_MONOTONIC,[], - [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland")], - [[#include ]]) -AC_CHECK_HEADERS([execinfo.h]) +AC_ARG_ENABLE([libraries], + [AC_HELP_STRING([--disable-libraries], + [Disable compilation of wayland libraries])], + [], + [enable_libraries=yes]) AC_ARG_ENABLE([scanner], [AC_HELP_STRING([--disable-scanner], @@ -79,11 +74,26 @@ AC_ARG_ENABLE([documentation], AM_CONDITIONAL(ENABLE_SCANNER, test "x$enable_scanner" = xyes) +AM_CONDITIONAL(ENABLE_LIBRARIES, test "x$enable_libraries" = xyes) + AC_ARG_WITH(icondir, [ --with-icondir= Look for cursor icons here], [ ICONDIR=$withval], [ ICONDIR=${datadir}/icons]) AC_SUBST([ICONDIR]) +if test "x$enable_libraries" = "xyes"; then + AC_CHECK_DECL(SFD_CLOEXEC,[], + [AC_MSG_ERROR("SFD_CLOEXEC is needed to compile wayland libraries")], + [[#include ]]) + AC_CHECK_DECL(TFD_CLOEXEC,[], + [AC_MSG_ERROR("TFD_CLOEXEC is needed to compile wayland libraries")], + [[#include ]]) + AC_CHECK_DECL(CLOCK_MONOTONIC,[], + [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland libraries")], + [[#include ]]) + AC_CHECK_HEADERS([execinfo.h]) +fi + if test "x$enable_scanner" = "xyes"; then PKG_CHECK_MODULES(EXPAT, [expat], [], [AC_CHECK_HEADERS(expat.h, [], From 0e979d82d249c4c0815ea82816fcf186a6862e2a Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 17 Jun 2015 15:13:51 -0500 Subject: [PATCH 0169/1152] build: Build a subset of libwayland_util when not building libraries The scanner doesn't need anything but wayland-util.c/.h so we can shrink wayland-util when not building the main libraries. Signed-off-by: Derek Foreman Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- Makefile.am | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 31adc973..845c1167 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,20 +34,23 @@ else wayland_scanner = wayland-scanner endif -libwayland_util_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) +libwayland_util_la_CFLAGS = $(GCC_CFLAGS) libwayland_util_la_SOURCES = \ - src/connection.c \ src/wayland-util.c \ - src/wayland-util.h \ - src/wayland-os.c \ - src/wayland-os.h \ - src/wayland-private.h + src/wayland-util.h noinst_LTLIBRARIES = libwayland-util.la if ENABLE_LIBRARIES lib_LTLIBRARIES = libwayland-server.la libwayland-client.la +libwayland_util_la_CFLAGS += $(FFI_CFLAGS) +libwayland_util_la_SOURCES += \ + src/connection.c \ + src/wayland-os.c \ + src/wayland-os.h \ + src/wayland-private.h + include_HEADERS = \ src/wayland-util.h \ src/wayland-server.h \ From bc3b66d5c194b9238126f7bc954142a07fe44f0e Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 17 Jun 2015 15:13:52 -0500 Subject: [PATCH 0170/1152] build: Don't depend on libffi unless we're building libraries When building just the scanner or docs it's not required. This can reduce requirements for a host cross compiling wayland, since only the scanner needs to be built natively. Signed-off-by: Derek Foreman Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 39e31072..3fa3cf4d 100644 --- a/configure.ac +++ b/configure.ac @@ -45,7 +45,6 @@ LT_PREREQ([2.2]) LT_INIT PKG_PROG_PKG_CONFIG() -PKG_CHECK_MODULES(FFI, [libffi]) if test "x$GCC" = "xyes"; then GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden" @@ -82,6 +81,7 @@ AC_ARG_WITH(icondir, [ --with-icondir= Look for cursor icons here], AC_SUBST([ICONDIR]) if test "x$enable_libraries" = "xyes"; then + PKG_CHECK_MODULES(FFI, [libffi]) AC_CHECK_DECL(SFD_CLOEXEC,[], [AC_MSG_ERROR("SFD_CLOEXEC is needed to compile wayland libraries")], [[#include ]]) From 356a48fcfb41cf08cf05c44c3b2d5d2c69e50201 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Jun 2015 13:27:29 +1000 Subject: [PATCH 0171/1152] doc: move project-specific doxygen settings to the end of the doxygen file Rather than having the settings hidden in the file somewhere move them to the end so it's clear which settings we intentionally override. Signed-off-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- doc/doxygen/wayland.doxygen.in | 53 ++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in index e64512f5..bab07443 100644 --- a/doc/doxygen/wayland.doxygen.in +++ b/doc/doxygen/wayland.doxygen.in @@ -1,5 +1,10 @@ # Doxyfile 1.7.6.1 +################################################################################# +# WARNING: do not edit options in-place. Append them to the end of this +# file instead. +################################################################################# + # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # @@ -26,13 +31,13 @@ DOXYFILE_ENCODING = UTF-8 # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. -PROJECT_NAME = "Wayland" +PROJECT_NAME = "My Project" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = @VERSION@ +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer @@ -52,7 +57,7 @@ PROJECT_LOGO = # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = @top_builddir@/doc/doxygen +OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output @@ -151,7 +156,7 @@ SHORT_NAMES = NO # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) -JAVADOC_AUTOBRIEF = YES +JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style @@ -184,7 +189,7 @@ SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. -TAB_SIZE = 8 +TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". @@ -193,7 +198,7 @@ TAB_SIZE = 8 # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. -ALIASES += comment{1}="/* \1 */" +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding @@ -573,7 +578,7 @@ CITE_BIB_FILES = # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. -QUIET = YES +QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank @@ -830,7 +835,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. -GENERATE_HTML = NO +GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be @@ -910,7 +915,7 @@ HTML_COLORSTYLE_GAMMA = 80 # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. -HTML_TIMESTAMP = YES +HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the @@ -1177,7 +1182,7 @@ SERVER_BASED_SEARCH = NO # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. -GENERATE_LATEX = NO +GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be @@ -1337,7 +1342,7 @@ MAN_EXTENSION = .3 # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. -MAN_LINKS = YES +MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output @@ -1424,13 +1429,13 @@ ENABLE_PREPROCESSING = YES # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. -MACRO_EXPANSION = YES +MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. -EXPAND_ONLY_PREDEF = YES +EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. @@ -1458,7 +1463,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = WL_EXPORT= +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. @@ -1721,7 +1726,7 @@ DOT_TRANSPARENT = NO # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. -DOT_MULTI_TARGETS = YES +DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and @@ -1734,3 +1739,21 @@ GENERATE_LEGEND = YES # the various graphs. DOT_CLEANUP = YES + + +# Wayland-specific overrides +PROJECT_NAME = "Wayland" +PROJECT_NUMBER = @VERSION@ +OUTPUT_DIRECTORY = @top_builddir@/doc/doxygen +JAVADOC_AUTOBRIEF = YES +TAB_SIZE = 8 +QUIET = YES +HTML_TIMESTAMP = YES +GENERATE_LATEX = NO +MAN_LINKS = YES +PREDEFINED = WL_EXPORT= +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +DOT_MULTI_TARGETS = YES +ALIASES += comment{1}="/* \1 */" +GENERATE_HTML = NO From 82a6fec962e73d71c084b65760be945f31e250fb Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Jun 2015 13:28:49 +1000 Subject: [PATCH 0172/1152] doc: drop the default doxygen tags Signed-off-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- doc/doxygen/wayland.doxygen.in | 1743 -------------------------------- 1 file changed, 1743 deletions(-) diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in index bab07443..fb76b123 100644 --- a/doc/doxygen/wayland.doxygen.in +++ b/doc/doxygen/wayland.doxygen.in @@ -1,1746 +1,3 @@ -# Doxyfile 1.7.6.1 - -################################################################################# -# WARNING: do not edit options in-place. Append them to the end of this -# file instead. -################################################################################# - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" "). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = "My Project" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# style sheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the -# mathjax.org site, so you can quickly see the result without installing -# MathJax, but it is strongly recommended to install a local copy of MathJax -# before deployment. - -MATHJAX_RELPATH = http://www.mathjax.org/mathjax - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - - # Wayland-specific overrides PROJECT_NAME = "Wayland" PROJECT_NUMBER = @VERSION@ From 40925634e6d41cc3b9edd94335b6551826157c9c Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 12 Jun 2015 16:44:15 -0700 Subject: [PATCH 0173/1152] publican: Update docs license from MIT "X11" to MIT "Expat" style Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- doc/publican/sources/Book_Info.xml | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/doc/publican/sources/Book_Info.xml b/doc/publican/sources/Book_Info.xml index 38e5bfce..e9e5ff0d 100644 --- a/doc/publican/sources/Book_Info.xml +++ b/doc/publican/sources/Book_Info.xml @@ -40,30 +40,30 @@ Copyright &YEAR; &HOLDER; - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this - permission notice appear in supporting documentation, and that - the name of the copyright holders not be used in advertising or - publicity pertaining to distribution of the software without - specific, written prior permission. The copyright holders make - no representations about the suitability of this software for - any purpose. It is provided "as is" without express or implied - warranty. - + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO - THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE COPYRIGHT - HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL - DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE - USE OR PERFORMANCE OF THIS SOFTWARE. - + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + From a8a86010a660ec157b91a689763f2f66406f6e21 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 12 Jun 2015 16:44:16 -0700 Subject: [PATCH 0174/1152] cursor: Update printed license from MIT "X11" to MIT "Expat" The code generates a cursor-data.h file, with licensing information. Change this from the MIT "X11" license to MIT "Expat" license for consistency with the rest of Wayland. Signed-off-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- cursor/convert_font.c | 52 +++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/cursor/convert_font.c b/cursor/convert_font.c index df40ca32..45b6ac6b 100644 --- a/cursor/convert_font.c +++ b/cursor/convert_font.c @@ -333,30 +333,38 @@ reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name, } } -/* From http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c */ +/* + * Originally from + * http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c + * Changed to the MIT "Expat" style license for Wayland.. + */ static const char cursor_licence[] = "/*\n" - "* Copyright 1999 SuSE, Inc.\n" - "*\n" - "* Permission to use, copy, modify, distribute, and sell this software and its\n" - "* documentation for any purpose is hereby granted without fee, provided that\n" - "* the above copyright notice appear in all copies and that both that\n" - "* copyright notice and this permission notice appear in supporting\n" - "* documentation, and that the name of SuSE not be used in advertising or\n" - "* publicity pertaining to distribution of the software without specific,\n" - "* written prior permission. SuSE makes no representations about the\n" - "* suitability of this software for any purpose. It is provided \"as is\"\n" - "* without express or implied warranty.\n" - "*\n" - "* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL\n" - "* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE\n" - "* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n" - "* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n" - "* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n" - "* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" - "*\n" - "* Author: Keith Packard, SuSE, Inc.\n" - "*/\n"; + "* Copyright 1999 SuSE, Inc.\n" + "*\n" + "* Permission is hereby granted, free of charge, to any person obtaining\n" + "* a copy of this software and associated documentation files (the\n" + "* \"Software\"), to deal in the Software without restriction, including\n" + "* without limitation the rights to use, copy, modify, merge, publish,\n" + "* distribute, sublicense, and/or sell copies of the Software, and to\n" + "* permit persons to whom the Software is furnished to do so, subject to\n" + "* the following conditions:\n" + "*\n" + "* The above copyright notice and this permission notice (including the\n" + "* next paragraph) shall be included in all copies or substantial\n" + "* portions of the Software.\n" + "*\n" + "* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n" + "* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n" + "* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n" + "* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n" + "* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n" + "* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n" + "* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n" + "* SOFTWARE.\n" + "*\n" + "* Author: Keith Packard, SuSE, Inc.\n" + "*/\n"; static void write_output_file(struct reconstructed_glyph *glyphs, int n) From 4cdc51034c83771fcde1fdf39beee8aa582dbb8c Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 18 Jun 2015 11:27:21 -0500 Subject: [PATCH 0175/1152] build: Use AM_CFLAGS instead of GCC_CFLAGS everywhere This will make it easier if we ever want to add new flags to everything in the future. Signed-off-by: Derek Foreman Reviewed-by: Jon A. Cruz Reviewed-by: Pekka Paalanen --- Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 845c1167..58f55953 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,7 +34,7 @@ else wayland_scanner = wayland-scanner endif -libwayland_util_la_CFLAGS = $(GCC_CFLAGS) +libwayland_util_la_CFLAGS = $(AM_CFLAGS) libwayland_util_la_SOURCES = \ src/wayland-util.c \ src/wayland-util.h @@ -65,7 +65,7 @@ nodist_include_HEADERS = \ protocol/wayland-server-protocol.h \ protocol/wayland-client-protocol.h -libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -pthread +libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm libwayland_server_la_LDFLAGS = -version-info 1:0:1 libwayland_server_la_SOURCES = \ @@ -77,7 +77,7 @@ nodist_libwayland_server_la_SOURCES = \ protocol/wayland-server-protocol.h \ protocol/wayland-protocol.c -libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -pthread +libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm libwayland_client_la_LDFLAGS = -version-info 3:0:3 libwayland_client_la_SOURCES = \ @@ -131,7 +131,7 @@ libwayland_cursor_la_LIBADD = libwayland-client.la pkgconfig_DATA += cursor/wayland-cursor.pc libwayland_cursor_la_CFLAGS = \ - $(GCC_CFLAGS) \ + $(AM_CFLAGS) \ -I$(top_builddir)/src \ -I$(top_srcdir)/src \ -DICONDIR=\"$(ICONDIR)\" From ab254f7efe067176d2f2eda672b773b228f78e2d Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 18 Jun 2015 11:48:30 -0500 Subject: [PATCH 0176/1152] cosmetic: gratuitous whitespace changes in event-loop.c Signed-off-by: Derek Foreman Reviewed-by: Jon A. Cruz Reviewed-by: Pekka Paalanen --- src/event-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index d1e03fae..130c7beb 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -199,7 +199,7 @@ wl_event_loop_add_timer(struct wl_event_loop *loop, source->base.interface = &timer_source_interface; source->base.fd = timerfd_create(CLOCK_MONOTONIC, - TFD_CLOEXEC | TFD_NONBLOCK); + TFD_CLOEXEC | TFD_NONBLOCK); source->func = func; return add_source(loop, &source->base, WL_EVENT_READABLE, data); From c2547c70a739d74f02979a8b590018ad6cb440d8 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 19 Jun 2015 15:58:01 -0700 Subject: [PATCH 0177/1152] tests: Don't increment variables inside an assert() Addresses this warning found by Denis Denisov: [tests/array-test.c:137]: (warning) Assert statement modifies 'i'. Signed-off-by: Bryce Harrington Reviewed-by: Jon A. Cruz --- tests/array-test.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/array-test.c b/tests/array-test.c index 37b9afd5..fe53240e 100644 --- a/tests/array-test.c +++ b/tests/array-test.c @@ -126,7 +126,8 @@ TEST(array_for_each) { static const int elements[] = { 77, 12, 45192, 53280, 334455 }; struct wl_array array; - int *p, i; + int *p; + int i; wl_array_init(&array); for (i = 0; i < 5; i++) { @@ -136,8 +137,10 @@ TEST(array_for_each) } i = 0; - wl_array_for_each(p, &array) - assert(*p == elements[i++]); + wl_array_for_each(p, &array) { + assert(*p == elements[i]); + i++; + } assert(i == 5); wl_array_release(&array); From ba731f951c150ee83f0b8af03feec3fa18425ebf Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Fri, 3 Jul 2015 09:33:23 +0200 Subject: [PATCH 0178/1152] fixed-benchmark: remove unused arguments in main Fixed benchmark uses main(int argc, char *argv[]) but does not use the arguments, so we can replace them with void Signed-off-by: Marek Chalupa Reviewed-by: Bryce Harrington --- tests/fixed-benchmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixed-benchmark.c b/tests/fixed-benchmark.c index 8d73c83f..277eccec 100644 --- a/tests/fixed-benchmark.c +++ b/tests/fixed-benchmark.c @@ -96,7 +96,7 @@ benchmark(const char *s, void (*f)(void)) s, elapsed.tv_sec, elapsed.tv_nsec); } -int main(int argc, char *argv[]) +int main(void) { benchmark("noop", noop_conversion); benchmark("magic", magic_conversion); From 21f80b89826d07bf687de35a1992a0b9bca3a51d Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Wed, 1 Jul 2015 22:51:01 +0100 Subject: [PATCH 0179/1152] build: always build wayland-scanner The previous idiom for building a cross-compiled Wayland is to build once for the build host (with --enable-scanner --disable-libraries) to get a wayland-scanner binary that can then be used in a cross-compile (with --disable-scanner). The problem with this is that the cross wayland is missing a wayland-scanner binary, which means you then can't do any Wayland development on the target. Instead, always build wayland-scanner for the target and change --enable/disable-scanner to --with/without-host-scanner. Normal builds use the default of --without-host-scanner and run the wayland-scanner it just built, and cross-compiled builds pass --with-host-scanner to use a previously built host scanner but still get a wayland-scanner to install. (a theoretically neater solution would be to build two scanners if required (one to run and one to install), but automake makes this overly complicated) [daniels: Bikeshedded naming with Ross's OK.] Signed-off-by: Ross Burton Reviewed-by: Daniel Stone --- Makefile.am | 9 +++++---- configure.ac | 32 +++++++++++++++----------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Makefile.am b/Makefile.am index 58f55953..2dbc2165 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,16 +22,17 @@ dist_pkgdata_DATA = \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = -if ENABLE_SCANNER -wayland_scanner = $(top_builddir)/wayland-scanner bin_PROGRAMS = wayland-scanner wayland_scanner_SOURCES = src/scanner.c wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS) wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la -$(BUILT_SOURCES) : wayland-scanner pkgconfig_DATA += src/wayland-scanner.pc -else + +if USE_HOST_SCANNER wayland_scanner = wayland-scanner +else +$(BUILT_SOURCES) : wayland-scanner +wayland_scanner = $(top_builddir)/wayland-scanner endif libwayland_util_la_CFLAGS = $(AM_CFLAGS) diff --git a/configure.ac b/configure.ac index 3fa3cf4d..7166f529 100644 --- a/configure.ac +++ b/configure.ac @@ -59,11 +59,11 @@ AC_ARG_ENABLE([libraries], [], [enable_libraries=yes]) -AC_ARG_ENABLE([scanner], - [AC_HELP_STRING([--disable-scanner], - [Disable compilation of wayland-scanner])], +AC_ARG_WITH([host-scanner], + [AC_HELP_STRING([--with-host-scanner], + [Use installed wayland-scanner from host PATH during build])], [], - [enable_scanner=yes]) + [with_host_scanner=no]) AC_ARG_ENABLE([documentation], [AC_HELP_STRING([--disable-documentation], @@ -71,7 +71,7 @@ AC_ARG_ENABLE([documentation], [], [enable_documentation=yes]) -AM_CONDITIONAL(ENABLE_SCANNER, test "x$enable_scanner" = xyes) +AM_CONDITIONAL(USE_HOST_SCANNER, test "x$with_host_scanner" = xyes) AM_CONDITIONAL(ENABLE_LIBRARIES, test "x$enable_libraries" = xyes) @@ -94,18 +94,16 @@ if test "x$enable_libraries" = "xyes"; then AC_CHECK_HEADERS([execinfo.h]) fi -if test "x$enable_scanner" = "xyes"; then - PKG_CHECK_MODULES(EXPAT, [expat], [], - [AC_CHECK_HEADERS(expat.h, [], - [AC_MSG_ERROR([Can't find expat.h. Please install expat.])]) - SAVE_LIBS="$LIBS" - AC_SEARCH_LIBS(XML_ParserCreate, expat, [], - [AC_MSG_ERROR([Can't find expat library. Please install expat.])]) - EXPAT_LIBS="$LIBS" - LIBS="$SAVE_LIBS" - AC_SUBST(EXPAT_LIBS) - ]) -fi +PKG_CHECK_MODULES(EXPAT, [expat], [], + [AC_CHECK_HEADERS(expat.h, [], + [AC_MSG_ERROR([Can't find expat.h. Please install expat.])]) + SAVE_LIBS="$LIBS" + AC_SEARCH_LIBS(XML_ParserCreate, expat, [], + [AC_MSG_ERROR([Can't find expat library. Please install expat.])]) + EXPAT_LIBS="$LIBS" + LIBS="$SAVE_LIBS" + AC_SUBST(EXPAT_LIBS) + ]) AC_PATH_PROG(XSLTPROC, xsltproc) AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"]) From de1489564c4b9bdeeb836f0c73d8786eecba174a Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 18 Jun 2015 17:47:22 -0500 Subject: [PATCH 0180/1152] build: Build libwayland-private This splits the bulk of libwayland-util into libwayland-private. libwayland-util (which is just wayland-util.c) is for use with the scanner. libwayland-private is everything else. Most things will want to link both libs. Signed-off-by: Derek Foreman Reviewed-by: Peter Hutterer --- Makefile.am | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2dbc2165..9114d982 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,10 +43,11 @@ libwayland_util_la_SOURCES = \ noinst_LTLIBRARIES = libwayland-util.la if ENABLE_LIBRARIES +noinst_LTLIBRARIES += libwayland-private.la lib_LTLIBRARIES = libwayland-server.la libwayland-client.la -libwayland_util_la_CFLAGS += $(FFI_CFLAGS) -libwayland_util_la_SOURCES += \ +libwayland_private_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) +libwayland_private_la_SOURCES = \ src/connection.c \ src/wayland-os.c \ src/wayland-os.h \ @@ -67,7 +68,7 @@ nodist_include_HEADERS = \ protocol/wayland-client-protocol.h libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread -libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm +libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la -lrt -lm libwayland_server_la_LDFLAGS = -version-info 1:0:1 libwayland_server_la_SOURCES = \ src/wayland-server.c \ @@ -79,7 +80,7 @@ nodist_libwayland_server_la_SOURCES = \ protocol/wayland-protocol.c libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread -libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm +libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la -lrt -lm libwayland_client_la_LDFLAGS = -version-info 3:0:3 libwayland_client_la_SOURCES = \ src/wayland-client.c @@ -176,6 +177,7 @@ libtest_runner_la_SOURCES = \ tests/test-compositor.h \ tests/test-compositor.c libtest_runner_la_LIBADD = \ + libwayland-private.la \ libwayland-util.la \ libwayland-client.la \ libwayland-server.la \ @@ -230,4 +232,4 @@ os_wrappers_test_LDADD = libtest-runner.la exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la -endif +endif #ENABLE_LIBRARIES From 1c12bf48af2a154787db8dc0561c73d10e074450 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Thu, 30 Jul 2015 18:18:25 -0700 Subject: [PATCH 0181/1152] gitignore: Ignore some dist generated files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a59564a1..33e809cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ +*.announce *.deps *.jpg *.la *.lo *.o *.pc +*.sig *.so *.swp *.3 From 87fab2e36cfc9b1ac782e26b5717518490176a2e Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 30 Jul 2015 15:07:20 +0200 Subject: [PATCH 0182/1152] scanner: refactor creating objects wrap creating and initializing objects (structures) into functions and use them in the code. v2. make create_.* functions consistent (no func will return NULL) Signed-off-by: Marek Chalupa Reviewed-by: Bryce Harrington --- src/scanner.c | 164 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 53 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 7d8cfb91..da33818b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1,6 +1,7 @@ /* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation + * Copyright © 2015 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -315,6 +316,108 @@ is_nullable_type(struct arg *arg) } } +static struct message * +create_message(struct location loc, const char *name) +{ + struct message *message; + + message = xmalloc(sizeof *message); + message->loc = loc; + message->name = xstrdup(name); + message->uppercase_name = uppercase_dup(name); + wl_list_init(&message->arg_list); + message->arg_count = 0; + message->new_id_count = 0; + message->description = NULL; + + return message; +} + +static struct arg * +create_arg(const char *name) +{ + struct arg *arg; + + arg = xmalloc(sizeof *arg); + arg->name = xstrdup(name); + arg->summary = NULL; + arg->interface_name = NULL; + + return arg; +} + +static bool +set_arg_type(struct arg *arg, const char *type) +{ + if (strcmp(type, "int") == 0) + arg->type = INT; + else if (strcmp(type, "uint") == 0) + arg->type = UNSIGNED; + else if (strcmp(type, "fixed") == 0) + arg->type = FIXED; + else if (strcmp(type, "string") == 0) + arg->type = STRING; + else if (strcmp(type, "array") == 0) + arg->type = ARRAY; + else if (strcmp(type, "fd") == 0) + arg->type = FD; + else if (strcmp(type, "new_id") == 0) + arg->type = NEW_ID; + else if (strcmp(type, "object") == 0) + arg->type = OBJECT; + else + return false; + + return true; +} + +static struct enumeration * +create_enumeration(const char *name) +{ + struct enumeration *enumeration; + + enumeration = xmalloc(sizeof *enumeration); + enumeration->name = xstrdup(name); + enumeration->uppercase_name = uppercase_dup(name); + enumeration->description = NULL; + + wl_list_init(&enumeration->entry_list); + + return enumeration; +} + +static struct entry * +create_entry(const char *name, const char *value) +{ + struct entry *entry; + + entry = xmalloc(sizeof *entry); + entry->name = xstrdup(name); + entry->uppercase_name = uppercase_dup(name); + entry->value = xstrdup(value); + + return entry; +} + +static struct interface * +create_interface(struct location loc, const char *name, int version) +{ + struct interface *interface; + + interface = xmalloc(sizeof *interface); + interface->loc = loc; + interface->name = xstrdup(name); + interface->uppercase_name = uppercase_dup(name); + interface->version = version; + interface->description = NULL; + interface->since = 1; + wl_list_init(&interface->request_list); + wl_list_init(&interface->event_list); + wl_list_init(&interface->enumeration_list); + + return interface; +} + static void start_element(void *data, const char *element_name, const char **atts) { @@ -376,32 +479,16 @@ start_element(void *data, const char *element_name, const char **atts) if (version == 0) fail(&ctx->loc, "no interface version given"); - interface = xmalloc(sizeof *interface); - interface->loc = ctx->loc; - interface->name = xstrdup(name); - interface->uppercase_name = uppercase_dup(name); - interface->version = version; - interface->description = NULL; - interface->since = 1; - wl_list_init(&interface->request_list); - wl_list_init(&interface->event_list); - wl_list_init(&interface->enumeration_list); + interface = create_interface(ctx->loc, name, version); + ctx->interface = interface; wl_list_insert(ctx->protocol->interface_list.prev, &interface->link); - ctx->interface = interface; } else if (strcmp(element_name, "request") == 0 || strcmp(element_name, "event") == 0) { if (name == NULL) fail(&ctx->loc, "no request name given"); - message = xmalloc(sizeof *message); - message->loc = ctx->loc; - message->name = xstrdup(name); - message->uppercase_name = uppercase_dup(name); - wl_list_init(&message->arg_list); - message->arg_count = 0; - message->new_id_count = 0; - message->description = NULL; + message = create_message(ctx->loc, name); if (strcmp(element_name, "request") == 0) wl_list_insert(ctx->interface->request_list.prev, @@ -440,28 +527,9 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no argument name given"); - arg = xmalloc(sizeof *arg); - arg->name = xstrdup(name); - - if (strcmp(type, "int") == 0) - arg->type = INT; - else if (strcmp(type, "uint") == 0) - arg->type = UNSIGNED; - else if (strcmp(type, "fixed") == 0) - arg->type = FIXED; - else if (strcmp(type, "string") == 0) - arg->type = STRING; - else if (strcmp(type, "array") == 0) - arg->type = ARRAY; - else if (strcmp(type, "fd") == 0) - arg->type = FD; - else if (strcmp(type, "new_id") == 0) { - arg->type = NEW_ID; - } else if (strcmp(type, "object") == 0) { - arg->type = OBJECT; - } else { + arg = create_arg(name); + if (!set_arg_type(arg, type)) fail(&ctx->loc, "unknown type (%s)", type); - } switch (arg->type) { case NEW_ID: @@ -472,8 +540,6 @@ start_element(void *data, const char *element_name, const char **atts) case OBJECT: if (interface_name) arg->interface_name = xstrdup(interface_name); - else - arg->interface_name = NULL; break; default: if (interface_name != NULL) @@ -491,7 +557,6 @@ start_element(void *data, const char *element_name, const char **atts) if (allow_null != NULL && !is_nullable_type(arg)) fail(&ctx->loc, "allow-null is only valid for objects, strings, and arrays"); - arg->summary = NULL; if (summary) arg->summary = xstrdup(summary); @@ -501,12 +566,7 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no enum name given"); - enumeration = xmalloc(sizeof *enumeration); - enumeration->name = xstrdup(name); - enumeration->uppercase_name = uppercase_dup(name); - enumeration->description = NULL; - wl_list_init(&enumeration->entry_list); - + enumeration = create_enumeration(name); wl_list_insert(ctx->interface->enumeration_list.prev, &enumeration->link); @@ -515,10 +575,8 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no entry name given"); - entry = xmalloc(sizeof *entry); - entry->name = xstrdup(name); - entry->uppercase_name = uppercase_dup(name); - entry->value = xstrdup(value); + entry = create_entry(name, value); + if (summary) entry->summary = xstrdup(summary); else From 289a75739b885821f94927caa50f8b1997130818 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 30 Jul 2015 15:07:21 +0200 Subject: [PATCH 0183/1152] scanner: get rid of leaks Free all the memory we have allocated during running. v2.: split creating objects and getting rid of leaks into two patches move check for NULL description into free_description v3.: rebase after previous patch fixes Signed-off-by: Marek Chalupa Reviewed-by: Bryce Harrington --- src/scanner.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index da33818b..19755eca 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -333,6 +333,15 @@ create_message(struct location loc, const char *name) return message; } +static void +free_arg(struct arg *arg) +{ + free(arg->name); + free(arg->interface_name); + free(arg->summary); + free(arg); +} + static struct arg * create_arg(const char *name) { @@ -371,6 +380,33 @@ set_arg_type(struct arg *arg, const char *type) return true; } +static void +free_description(struct description *desc) +{ + if (!desc) + return; + + free(desc->summary); + free(desc->text); + + free(desc); +} + +static void +free_message(struct message *message) +{ + struct arg *a, *a_next; + + free(message->name); + free(message->uppercase_name); + free_description(message->description); + + wl_list_for_each_safe(a, a_next, &message->arg_list, link) + free_arg(a); + + free(message); +} + static struct enumeration * create_enumeration(const char *name) { @@ -399,6 +435,32 @@ create_entry(const char *name, const char *value) return entry; } +static void +free_entry(struct entry *entry) +{ + free(entry->name); + free(entry->uppercase_name); + free(entry->value); + free(entry->summary); + + free(entry); +} + +static void +free_enumeration(struct enumeration *enumeration) +{ + struct entry *e, *e_next; + + free(enumeration->name); + free(enumeration->uppercase_name); + free_description(enumeration->description); + + wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link) + free_entry(e); + + free(enumeration); +} + static struct interface * create_interface(struct location loc, const char *name, int version) { @@ -418,6 +480,26 @@ create_interface(struct location loc, const char *name, int version) return interface; } +static void +free_interface(struct interface *interface) +{ + struct message *m, *next_m; + struct enumeration *e, *next_e; + + free(interface->name); + free(interface->uppercase_name); + free_description(interface->description); + + wl_list_for_each_safe(m, next_m, &interface->request_list, link) + free_message(m); + wl_list_for_each_safe(m, next_m, &interface->event_list, link) + free_message(m); + wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link) + free_enumeration(e); + + free(interface); +} + static void start_element(void *data, const char *element_name, const char **atts) { @@ -1107,7 +1189,7 @@ get_include_name(bool core, enum side side) static void emit_header(struct protocol *protocol, enum side side) { - struct interface *i; + struct interface *i, *i_next; struct wl_array types; const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; char **p, *prev; @@ -1160,7 +1242,7 @@ emit_header(struct protocol *protocol, enum side side) printf("\n"); - wl_list_for_each(i, &protocol->interface_list, link) { + wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) { emit_enumerations(i); @@ -1174,6 +1256,8 @@ emit_header(struct protocol *protocol, enum side side) emit_opcodes(&i->request_list, i); emit_stubs(&i->request_list, i); } + + free_interface(i); } printf("#ifdef __cplusplus\n" @@ -1289,7 +1373,7 @@ emit_messages(struct wl_list *message_list, static void emit_code(struct protocol *protocol) { - struct interface *i; + struct interface *i, *next; struct wl_array types; char **p, *prev; @@ -1324,7 +1408,7 @@ emit_code(struct protocol *protocol) } printf("};\n\n"); - wl_list_for_each(i, &protocol->interface_list, link) { + wl_list_for_each_safe(i, next, &protocol->interface_list, link) { emit_messages(&i->request_list, i, "requests"); emit_messages(&i->event_list, i, "events"); @@ -1347,9 +1431,21 @@ emit_code(struct protocol *protocol) printf("\t0, NULL,\n"); printf("};\n\n"); + + /* we won't need it any further */ + free_interface(i); } } +static void +free_protocol(struct protocol *protocol) +{ + free(protocol->name); + free(protocol->uppercase_name); + free(protocol->copyright); + free_description(protocol->description); +} + int main(int argc, char *argv[]) { struct parse_context ctx; @@ -1473,5 +1569,7 @@ int main(int argc, char *argv[]) break; } + free_protocol(&protocol); + return 0; } From 765040d1a72e4e698d40874d181e1d9a4677213c Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 30 Jul 2015 15:07:22 +0200 Subject: [PATCH 0184/1152] scanner: use zxalloc Use xzalloc instead of xmalloc. This allows us to get rid of manual initializing the memory to 0s and the code is shorter and cleaner Suggested by Bryce Harrington Signed-off-by: Marek Chalupa Reviewed-by: Bryce Harrington --- src/scanner.c | 83 +++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 19755eca..b0e9ef7b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -169,9 +169,15 @@ fail_on_null(void *p) } static void * -xmalloc(size_t s) +zalloc(size_t s) { - return fail_on_null(malloc(s)); + return calloc(s, 1); +} + +static void * +xzalloc(size_t s) +{ + return fail_on_null(zalloc(s)); } static char * @@ -321,14 +327,11 @@ create_message(struct location loc, const char *name) { struct message *message; - message = xmalloc(sizeof *message); + message = xzalloc(sizeof *message); message->loc = loc; message->name = xstrdup(name); message->uppercase_name = uppercase_dup(name); wl_list_init(&message->arg_list); - message->arg_count = 0; - message->new_id_count = 0; - message->description = NULL; return message; } @@ -347,10 +350,8 @@ create_arg(const char *name) { struct arg *arg; - arg = xmalloc(sizeof *arg); + arg = xzalloc(sizeof *arg); arg->name = xstrdup(name); - arg->summary = NULL; - arg->interface_name = NULL; return arg; } @@ -412,10 +413,9 @@ create_enumeration(const char *name) { struct enumeration *enumeration; - enumeration = xmalloc(sizeof *enumeration); + enumeration = xzalloc(sizeof *enumeration); enumeration->name = xstrdup(name); enumeration->uppercase_name = uppercase_dup(name); - enumeration->description = NULL; wl_list_init(&enumeration->entry_list); @@ -427,7 +427,7 @@ create_entry(const char *name, const char *value) { struct entry *entry; - entry = xmalloc(sizeof *entry); + entry = xzalloc(sizeof *entry); entry->name = xstrdup(name); entry->uppercase_name = uppercase_dup(name); entry->value = xstrdup(value); @@ -466,12 +466,11 @@ create_interface(struct location loc, const char *name, int version) { struct interface *interface; - interface = xmalloc(sizeof *interface); + interface = xzalloc(sizeof *interface); interface->loc = loc; interface->name = xstrdup(name); interface->uppercase_name = uppercase_dup(name); interface->version = version; - interface->description = NULL; interface->since = 1; wl_list_init(&interface->request_list); wl_list_init(&interface->event_list); @@ -509,22 +508,18 @@ start_element(void *data, const char *element_name, const char **atts) struct arg *arg; struct enumeration *enumeration; struct entry *entry; - struct description *description; - const char *name, *type, *interface_name, *value, *summary, *since; - const char *allow_null; + struct description *description = NULL; + const char *name = NULL; + const char *type = NULL; + const char *interface_name = NULL; + const char *value = NULL; + const char *summary = NULL; + const char *since = NULL; + const char *allow_null = NULL; char *end; - int i, version; + int i, version = 0; ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); - name = NULL; - type = NULL; - version = 0; - interface_name = NULL; - value = NULL; - summary = NULL; - description = NULL; - since = NULL; - allow_null = NULL; for (i = 0; atts[i]; i += 2) { if (strcmp(atts[i], "name") == 0) name = atts[i + 1]; @@ -551,7 +546,6 @@ start_element(void *data, const char *element_name, const char **atts) ctx->protocol->name = xstrdup(name); ctx->protocol->uppercase_name = uppercase_dup(name); - ctx->protocol->description = NULL; } else if (strcmp(element_name, "copyright") == 0) { } else if (strcmp(element_name, "interface") == 0) { @@ -581,8 +575,6 @@ start_element(void *data, const char *element_name, const char **atts) if (type != NULL && strcmp(type, "destructor") == 0) message->destructor = 1; - else - message->destructor = 0; if (since != NULL) { int prev_errno = errno; @@ -629,15 +621,18 @@ start_element(void *data, const char *element_name, const char **atts) break; } - if (allow_null == NULL || strcmp(allow_null, "false") == 0) - arg->nullable = 0; - else if (strcmp(allow_null, "true") == 0) - arg->nullable = 1; - else - fail(&ctx->loc, "invalid value for allow-null attribute (%s)", allow_null); + if (allow_null) { + if (strcmp(allow_null, "true") == 0) + arg->nullable = 1; + else if (strcmp(allow_null, "false") != 0) + fail(&ctx->loc, + "invalid value for allow-null attribute (%s)", + allow_null); - if (allow_null != NULL && !is_nullable_type(arg)) - fail(&ctx->loc, "allow-null is only valid for objects, strings, and arrays"); + if (!is_nullable_type(arg)) + fail(&ctx->loc, + "allow-null is only valid for objects, strings, and arrays"); + } if (summary) arg->summary = xstrdup(summary); @@ -669,7 +664,7 @@ start_element(void *data, const char *element_name, const char **atts) if (summary == NULL) fail(&ctx->loc, "description without summary"); - description = xmalloc(sizeof *description); + description = xzalloc(sizeof *description); description->summary = xstrdup(summary); if (ctx->message) @@ -1519,15 +1514,17 @@ int main(int argc, char *argv[]) } } + /* initialize protocol structure */ + memset(&protocol, 0, sizeof protocol); wl_list_init(&protocol.interface_list); - protocol.type_index = 0; - protocol.null_run_length = 0; - protocol.copyright = NULL; protocol.core_headers = core_headers; + + /* initialize context */ memset(&ctx, 0, sizeof ctx); ctx.protocol = &protocol; - ctx.loc.filename = ""; + + /* create XML parser */ ctx.parser = XML_ParserCreate(NULL); XML_SetUserData(ctx.parser, &ctx); if (ctx.parser == NULL) { From bbe6795d9b36efd59a3468cbfd6a5eb735ad1ad1 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 30 Jul 2015 16:42:00 +0200 Subject: [PATCH 0185/1152] scanner: check sanity of version scanner does not complain if we put into version attribute things like -1 1x 1:3 etc. Signed-off-by: Marek Chalupa Reviewed-by: Bryce Harrington --- src/scanner.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index b0e9ef7b..9b41ae44 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "wayland-util.h" @@ -499,6 +500,29 @@ free_interface(struct interface *interface) free(interface); } +/* convert string to unsigned integer, + * in the case of error, return -1 */ +static int +strtouint(const char *str) +{ + long int ret; + char *end; + int prev_errno = errno; + + errno = 0; + ret = strtol(str, &end, 10); + if (errno != 0 || end == str || *end != '\0') + return -1; + + /* check range */ + if (ret < 0 || ret > INT_MAX) { + return -1; + } + + errno = prev_errno; + return (int)ret; +} + static void start_element(void *data, const char *element_name, const char **atts) { @@ -516,7 +540,6 @@ start_element(void *data, const char *element_name, const char **atts) const char *summary = NULL; const char *since = NULL; const char *allow_null = NULL; - char *end; int i, version = 0; ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); @@ -524,7 +547,9 @@ start_element(void *data, const char *element_name, const char **atts) if (strcmp(atts[i], "name") == 0) name = atts[i + 1]; if (strcmp(atts[i], "version") == 0) - version = atoi(atts[i + 1]); + version = strtouint(atts[i + 1]); + if (version == -1) + fail(&ctx->loc, "wrong version (%s)", atts[i + 1]); if (strcmp(atts[i], "type") == 0) type = atts[i + 1]; if (strcmp(atts[i], "value") == 0) @@ -577,13 +602,9 @@ start_element(void *data, const char *element_name, const char **atts) message->destructor = 1; if (since != NULL) { - int prev_errno = errno; - errno = 0; - version = strtol(since, &end, 0); - if (errno != 0 || end == since || *end != '\0') - fail(&ctx->loc, - "invalid integer (%s)\n", since); - errno = prev_errno; + version = strtouint(since); + if (version == -1) + fail(&ctx->loc, "invalid integer (%s)\n", since); } else { version = 1; } From 441f9bb144efd561f0ac4bc4e672acc9703b5126 Mon Sep 17 00:00:00 2001 From: Elvis Lee Date: Fri, 31 Jul 2015 18:02:54 +0900 Subject: [PATCH 0186/1152] wayland-client : Fix queue_release not to call proxy_destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit proxy_destroy could be called twice by wl_proxy_destroy and wl_event_queue_release. Then, wl_map_remove was called twice for same object id. Signed-off-by: Elvis Lee Reviewed-by: Jonas Ådahl Reviewed-by: Daniel Stone --- src/wayland-client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 6450b67d..09c594ae 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -259,6 +259,7 @@ wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; struct wl_proxy *proxy; + bool proxy_destroyed; while (!wl_list_empty(&queue->event_list)) { closure = container_of(queue->event_list.next, @@ -268,10 +269,11 @@ wl_event_queue_release(struct wl_event_queue *queue) decrease_closure_args_refcount(closure); proxy = closure->proxy; - if (proxy->refcount == 1) - proxy_destroy(proxy); - else - --proxy->refcount; + proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); + + proxy->refcount--; + if (proxy_destroyed && !proxy->refcount) + free(proxy); wl_closure_destroy(closure); } From fb7e13021730d0a5516ecbd3712ea4235e05d24d Mon Sep 17 00:00:00 2001 From: Dima Ryazanov Date: Wed, 12 Aug 2015 19:34:31 -0700 Subject: [PATCH 0187/1152] client: require WAYLAND_DISPLAY to be set Although defaulting to wayland-0 seems convenient, it has an undesirable side effect: clients may unintentionally connect to the wrong compositor. Generally, it's safer to fail instead. Here's a real example: In Fedora 22, Gtk+ prefers Wayland over X11, though the default session is still a normal X11 Gnome session. When you launch a Gtk+ app, it will try Wayland, fail, then try X11, and succesfully start up. That works fine. Now suppose you launch Weston while running the Gnome session. Suddenly, all of the Gtk+ apps launched from Gnome will show up inside Weston instead. That's unexpected. There's also no good way to prevent that from happening (other than perhaps setting WAYLAND_DISPLAY to an invalid value when launching an app). Not using wayland-0 as the default will solve that problem: an app launched from the X11 Gnome session will use the X11 backend regardless of whether there's a wayland compositor running at the same time. Everything else should work as before. The compositor already sets the WAYLAND_DISPLAY when starting the session, so the lack of the default value should not make a difference to the user. Signed-off-by: Dima Ryazanov Acked-by: Pekka Paalanen Acked-by: Giulio Camuffo Acked-by: Daniel Stone Acked-by: Jasper St. Pierre Reviewed-by: Ryo Munakata [Pekka: dropped the wayland-server.c hunk, adjusted summary] Signed-off-by: Pekka Paalanen --- doc/man/wl_display_connect.xml | 5 ++--- doc/publican/sources/Protocol.xml | 8 ++++---- src/wayland-client.c | 10 ++++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/doc/man/wl_display_connect.xml b/doc/man/wl_display_connect.xml index 7e6e05c6..ded3cbd3 100644 --- a/doc/man/wl_display_connect.xml +++ b/doc/man/wl_display_connect.xml @@ -57,9 +57,8 @@ that was previously opened by a Wayland server. The server socket must be placed in XDG_RUNTIME_DIR for this function to find it. The name argument specifies the name of - the socket or NULL to use the default (which is - "wayland-0"). The environment variable - WAYLAND_DISPLAY replaces the default value. If + the socket or NULL to use the default + (which is the value of WAYLAND_DISPLAY). If WAYLAND_SOCKET is set, this function behaves like wl_display_connect_to_fd with the file-descriptor number taken from the environment variable. diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 477063be..9464953b 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -60,10 +60,10 @@ Wire Format The protocol is sent over a UNIX domain stream socket, where the endpoint - usually is named wayland-0 - (although it can be changed via WAYLAND_DISPLAY - in the environment). The protocol is message-based. A - message sent by a client to the server is called request. A message + name is determined by the WAYLAND_DISPLAY + environment variable. Its value will usually be + wayland-0. The protocol is message-based. + A message sent by a client to the server is called request. A message from the server to a client is called event. Every message is structured as 32-bit words, values are represented in the host's byte-order. diff --git a/src/wayland-client.c b/src/wayland-client.c index 09c594ae..ffbca4b0 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -764,8 +764,11 @@ connect_to_socket(const char *name) if (name == NULL) name = getenv("WAYLAND_DISPLAY"); - if (name == NULL) - name = "wayland-0"; + if (name == NULL) { + wl_log("error: WAYLAND_DISPLAY not set in the environment.\n"); + errno = ENOENT; + return -1; + } fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); if (fd < 0) @@ -869,8 +872,7 @@ wl_display_connect_to_fd(int fd) * \return A \ref wl_display object or \c NULL on failure * * Connect to the Wayland display named \c name. If \c name is \c NULL, - * its value will be replaced with the WAYLAND_DISPLAY environment - * variable if it is set, otherwise display "wayland-0" will be used. + * its value will be replaced with the WAYLAND_DISPLAY environment variable. * * \memberof wl_display */ From c0636ddcacc72c34a773f170aabdb46a5a21c275 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Sun, 16 Aug 2015 13:54:50 -0700 Subject: [PATCH 0188/1152] configure.ac: bump to version 1.8.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7166f529..0009857e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [8]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From c7dbaa1cfda68185b3b0d3665efdf4620c66531e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 17 Aug 2015 15:20:28 +0300 Subject: [PATCH 0189/1152] Revert "client: require WAYLAND_DISPLAY to be set" This reverts commit fb7e13021730d0a5516ecbd3712ea4235e05d24d. Developers have been trying to reduce the number of by default required environment variables, and the mentioned commit is a step backwards in that sense. The fundamental assumption is that a user has only one main (Wayland) display server where all programs should connect to by default, and do so with an a priori known socket name. The commit also broke various use cases in the wild, some accidentally due to other causes, some intentionally. This revert allows those use cases to continue. The original problem of running Weston in a window in an existing GNOME X11 session and getting applications unintentionally launched into Weston can be circumvented by letting Weston use a non-default socket name, leaving wayland-0 unused. Discussion: http://lists.freedesktop.org/archives/wayland-devel/2015-August/023927.html http://lists.freedesktop.org/archives/wayland-devel/2015-August/023937.html Cc: Dima Ryazanov Cc: Giulio Camuffo Cc: Daniel Stone Cc: Jasper St. Pierre Cc: Ryo Munakata Cc: Ray Strode Cc: Peter Hutterer Cc: Matthias Clasen Cc: Sjoerd Simons Signed-off-by: Pekka Paalanen Acked-by: Ray Strode Acked-by: Dima Ryazanov Reviewed-by: Bryce Harrington Acked-By: Sjoerd Simons Acked-By: Ryo Munakata Acked-by: Peter Hutterer --- doc/man/wl_display_connect.xml | 5 +++-- doc/publican/sources/Protocol.xml | 8 ++++---- src/wayland-client.c | 10 ++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/doc/man/wl_display_connect.xml b/doc/man/wl_display_connect.xml index ded3cbd3..7e6e05c6 100644 --- a/doc/man/wl_display_connect.xml +++ b/doc/man/wl_display_connect.xml @@ -57,8 +57,9 @@ that was previously opened by a Wayland server. The server socket must be placed in XDG_RUNTIME_DIR for this function to find it. The name argument specifies the name of - the socket or NULL to use the default - (which is the value of WAYLAND_DISPLAY). If + the socket or NULL to use the default (which is + "wayland-0"). The environment variable + WAYLAND_DISPLAY replaces the default value. If WAYLAND_SOCKET is set, this function behaves like wl_display_connect_to_fd with the file-descriptor number taken from the environment variable. diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 9464953b..477063be 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -60,10 +60,10 @@ Wire Format The protocol is sent over a UNIX domain stream socket, where the endpoint - name is determined by the WAYLAND_DISPLAY - environment variable. Its value will usually be - wayland-0. The protocol is message-based. - A message sent by a client to the server is called request. A message + usually is named wayland-0 + (although it can be changed via WAYLAND_DISPLAY + in the environment). The protocol is message-based. A + message sent by a client to the server is called request. A message from the server to a client is called event. Every message is structured as 32-bit words, values are represented in the host's byte-order. diff --git a/src/wayland-client.c b/src/wayland-client.c index ffbca4b0..09c594ae 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -764,11 +764,8 @@ connect_to_socket(const char *name) if (name == NULL) name = getenv("WAYLAND_DISPLAY"); - if (name == NULL) { - wl_log("error: WAYLAND_DISPLAY not set in the environment.\n"); - errno = ENOENT; - return -1; - } + if (name == NULL) + name = "wayland-0"; fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); if (fd < 0) @@ -872,7 +869,8 @@ wl_display_connect_to_fd(int fd) * \return A \ref wl_display object or \c NULL on failure * * Connect to the Wayland display named \c name. If \c name is \c NULL, - * its value will be replaced with the WAYLAND_DISPLAY environment variable. + * its value will be replaced with the WAYLAND_DISPLAY environment + * variable if it is set, otherwise display "wayland-0" will be used. * * \memberof wl_display */ From b16c0a5dfa829ff6cef707ed72907c5f88acf3cf Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 1 Sep 2015 16:51:30 -0700 Subject: [PATCH 0190/1152] configure.ac: bump to version 1.8.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0009857e..40b05789 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [8]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 8fd494995d000edbc9d4c1a1805d316ffdff8890 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 15 Sep 2015 20:16:37 -0700 Subject: [PATCH 0191/1152] configure.ac: bump to version 1.8.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 40b05789..5580066d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [8]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From b05668f0ad64ad9ba82e124965163daed4172ead Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Mon, 21 Sep 2015 16:51:16 -0700 Subject: [PATCH 0192/1152] configure.ac: bump to version 1.9.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5580066d..41cea2a9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [8]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [9]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From b31225f91bfa0efe176ff5c93d5830dd947f6671 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 22 Sep 2015 13:39:36 -0700 Subject: [PATCH 0193/1152] configure.ac: bump to version 1.9.90 for open development Master is open for new feature development again. Signed-off-by: Bryce Harrington --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 41cea2a9..ef269294 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [9]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From d20a0b875847ba193a3886160c89ba4dbb76a9a4 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 22 Sep 2015 09:56:24 +0300 Subject: [PATCH 0194/1152] Contributing: explain Patchwork Add general guidelines for using Patchwork, as we heavily rely on it nowadays. v2: - mention also Xwayland and libinput patch management - reword "if not found in Patchwork" - reword "Not applicable" - mention pwclient Cc: Bryce Harrington Cc: Olivier Fourdan Signed-off-by: Pekka Paalanen Reviewed-by: Bryce Harrington Reviewed-by: Olivier Fourdan --- doc/Contributing | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/doc/Contributing b/doc/Contributing index 39c3e394..fe906141 100644 --- a/doc/Contributing +++ b/doc/Contributing @@ -30,6 +30,81 @@ cope with the way git log presents them. See [2] for a recommend reading on writing commit messages. + +== Tracking patches and following up == + +Patchwork is used for tracking patches to Wayland and Weston: +http://patchwork.freedesktop.org/project/wayland/list/ + +Xwayland patches are tracked with the Xorg project, not here. + +Libinput patches, even though they use the same mailing list as Wayland, are +not tracked in the Wayland Patchwork. + +The following applies only to Wayland and Weston. + +If a patch is not found in Patchwork, there is a high possibility for it to be +forgotten. Patches attached to bug reports or not arriving to the mailing list +because of e.g. subscription issues will not be in Patchwork because Patchwork +only collects patches sent to the list. + +When you send a revised version of a patch, it would be very nice to mark your +old patch as superseded (or rejected, if that is applicable). You can change +the status of your own patches by registering to Patchwork - ownership is +identified by email address you use to register. Updating your patch status +appropriately will help maintainer work. + +The following patch states are found in Patchwork: + + New + Patches under discussion or not yet processed. + + Under review + Mostly unused state. + + Accepted + The patch is merged in the master branch upstream, as is or slightly + modified. + + Rejected + The idea or approach is rejected and cannot be fixed by revising + the patch. + + RFC + Request for comments, not meant to be merged as is. + + Not applicable + The email was not actually a patch, or the patch is not for Wayland or + Weston. Libinput patches are usually automatically ignored by Wayland + Patchwork, but if they get through, they will be marked as Not + applicable. + + Changes requested + Reviewers determined that changes to the patch are needed. The + submitter is expected to send a revised version. (You should + not wait for your patch to be set to this state before revising, + though.) + + Awaiting upstream + Mostly unused as the patch is waiting for upstream actions but + is not shown in the default list, which means it is easy to + overlook. + + Superseded + A revised version of the patch has been submitted. + + Deferred + Used mostly during freeze periods before releases, to temporarily + hide patches that cannot be merged during a freeze. + +Note, that in the default listing, only patches in New or Under review are +shown. + +There is also a command line interface to Patchwork called 'pwclient', see +http://patchwork.freedesktop.org/project/wayland/ +for links where to get it and the sample .pwclientrc for Wayland/Weston. + + == Coding style == You should follow the style of the file you're editing. In general, we From e0b2166c9977b0bd1ab2aaff2604f6215f5c48a8 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Thu, 1 Oct 2015 18:13:29 -0700 Subject: [PATCH 0195/1152] scanner: Close input resource when done to prevent leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses this error reported by Denis Denisov: [src/scanner.c:1415]: (error) Resource leak: input Signed-off-by: Bryce Harrington v2: Also close input for other exit points in main. Signed-off-by: Bryce Harrington Reviewed-by: Jonas Ådahl Acked-by: Pekka Paalanen Reviewed-by: David FORT --- src/scanner.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index 9b41ae44..5504fcec 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1531,6 +1531,7 @@ int main(int argc, char *argv[]) if (freopen(argv[2], "w", stdout) == NULL) { fprintf(stderr, "Could not open output file: %s\n", strerror(errno)); + fclose(input); exit(EXIT_FAILURE); } } @@ -1550,6 +1551,7 @@ int main(int argc, char *argv[]) XML_SetUserData(ctx.parser, &ctx); if (ctx.parser == NULL) { fprintf(stderr, "failed to create parser\n"); + fclose(input); exit(EXIT_FAILURE); } @@ -1561,6 +1563,7 @@ int main(int argc, char *argv[]) len = fread(buf, 1, XML_BUFFER_SIZE, input); if (len < 0) { fprintf(stderr, "fread: %m\n"); + fclose(input); exit(EXIT_FAILURE); } if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) { @@ -1569,6 +1572,7 @@ int main(int argc, char *argv[]) XML_GetCurrentLineNumber(ctx.parser), XML_GetCurrentColumnNumber(ctx.parser), XML_ErrorString(XML_GetErrorCode(ctx.parser))); + fclose(input); exit(EXIT_FAILURE); } } while (len > 0); @@ -1588,6 +1592,7 @@ int main(int argc, char *argv[]) } free_protocol(&protocol); + fclose(input); return 0; } From e74cde739eee62be15d85ad62ce8b7c8bbd90d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 2 Oct 2015 17:32:52 +0800 Subject: [PATCH 0196/1152] client: Fix minor grammar issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl Reviewed-by: Bryce Harrington --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 09c594ae..1d5f6446 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -157,7 +157,7 @@ display_fatal_error(struct wl_display *display, int error) /** * This function is called for error events * and indicates that in some object an error occurred. - * Difference between this function and display_fatal_error() + * The difference between this function and display_fatal_error() * is that this one handles errors that will come by wire, * whereas display_fatal_error() is called for local errors. * From f755dbde26d817b5937d8cebc8aa55191bddaaf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 2 Oct 2015 17:32:53 +0800 Subject: [PATCH 0197/1152] client: Reword and add documentation about the marshal functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some rewording to improve grammar a bit with some additions about the type expectations of va_list arguments. Signed-off-by: Jonas Ådahl Reviewed-by: Bryce Harrington --- src/wayland-client.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 1d5f6446..f454b94b 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -562,9 +562,9 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, * \param args Extra arguments for the given request * \param interface The interface to use for the new proxy * - * Translates the request given by opcode and the extra arguments into the - * wire format and write it to the connection buffer. This version takes an - * array of the union type wl_argument. + * This function translates a request given an opcode, an interface and a + * wl_argument array to the wire format and writes it to the connection + * buffer. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned @@ -656,8 +656,10 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) * \param ... Extra arguments for the given request * \return A new wl_proxy for the new_id argument or NULL on error * - * Translates the request given by opcode and the extra arguments into the - * wire format and write it to the connection buffer. + * This function translates a request given an opcode, an interface and extra + * arguments to the wire format and writes it to the connection buffer. The + * types of the extra arguments must correspond to the argument types of the + * method associated with the opcode in the interface. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned From 5e0ed917744f2f881956e91ebe971073fd0a7c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 2 Oct 2015 17:32:54 +0800 Subject: [PATCH 0198/1152] client: Be more clear about when one must call wl_display_flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blocking in general is not what means it is required to flush, but blocking on input from the wl_display file descriptor. Signed-off-by: Jonas Ådahl Reviewed-by: Bryce Harrington --- src/wayland-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index f454b94b..007de0fe 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1777,10 +1777,10 @@ wl_display_get_protocol_error(struct wl_display *display, * \param display The display context object * \return The number of bytes sent on success or -1 on failure * - * Send all buffered data on the client side to the server. Clients - * should call this function before blocking. On success, the number - * of bytes sent to the server is returned. On failure, this - * function returns -1 and errno is set appropriately. + * Send all buffered data on the client side to the server. Clients should + * always call this function before blocking on input from the display fd. + * On success, the number of bytes sent to the server is returned. On + * failure, this function returns -1 and errno is set appropriately. * * wl_display_flush() never blocks. It will write as much data as * possible, but if all data could not be written, errno will be set From 99c34e58dbc9357527d374abf3bb5ca952d91942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 2 Oct 2015 17:32:56 +0800 Subject: [PATCH 0199/1152] client: Improve wl_display_roundtrip(_queue)() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the wording a bit to describe how it is done (which explains to the name of the function) as well as a note about that we actually will dispatch events that are received. Signed-off-by: Jonas Ådahl Reviewed-by: Bryce Harrington --- src/wayland-client.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 007de0fe..97966b8a 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -962,8 +962,12 @@ static const struct wl_callback_listener sync_listener = { * \param queue The queue on which to run the roundtrip * \return The number of dispatched events on success or -1 on failure * - * Blocks until the server processes all currently issued requests and - * sends out pending events on the event queue. + * This function blocks until the server has processed all currently issued + * requests by sending a request to the display server and waiting for a + * reply before returning. + * + * \note This function may dispatch other events being received on the given + * queue. * * \note This function uses wl_display_dispatch_queue() internally. If you * are using wl_display_read_events() from more threads, don't use this function @@ -999,8 +1003,12 @@ wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *qu * \param display The display context object * \return The number of dispatched events on success or -1 on failure * - * Blocks until the server process all currently issued requests and - * sends out pending events on the default event queue. + * This function blocks until the server has processed all currently issued + * requests by sending a request to the display server and waiting for a reply + * before returning. + * + * \note This function may dispatch other events being received on the default + * queue. * * \note This function uses wl_display_dispatch_queue() internally. If you * are using wl_display_read_events() from more threads, don't use this function From b6809e5a8051fd193fe4b041a3245c22432195db Mon Sep 17 00:00:00 2001 From: FORT David Date: Fri, 2 Oct 2015 14:20:12 +0200 Subject: [PATCH 0200/1152] wayland: add a release request on wl_seat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required if we want to correctly remove a wl_seat compositor-side. A wl_seat is announced as a global object, then it is bound by the client. When the compositor wants to remove the seat, it shall announce the global removal of the object. The client can then call the release request on the wl_seat (which means I won't use that object anymore). Acked-by: Derek Foreman Reviewed-by: Jonas Ådahl --- protocol/wayland.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 42c93090..59819e9a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1329,7 +1329,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -1400,6 +1400,15 @@ + + + + + Using this request client can tell the server that it is not going to + use the seat object anymore. + + + From 7c9135e1cf69d36a38e4ea4805f4899751079ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 25 Sep 2015 11:56:46 +0800 Subject: [PATCH 0201/1152] client: Move prepare read documentation to .._prepare_read_queue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the documentation we refer to "an event queue" in various places and from the beginning it is unclear what event queue this means. So, instead of having a paragraph in the end mentioning this, move the detailed documentation to the function with the queue explicitly passed. Signed-off-by: Jonas Ådahl Reviewed-by: Bryce Harrington --- src/wayland-client.c | 154 ++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 81 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 97966b8a..b1c600f4 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1369,20 +1369,81 @@ err: return -1; } -/** Prepare to read events from the display to this queue +/** Prepare to read events from the display's file descriptor to a queue * * \param display The display context object * \param queue The event queue to use * \return 0 on success or -1 if event queue was not empty * - * Atomically makes sure the queue is empty and stops any other thread - * from placing events into this (or any) queue. Caller must - * eventually call either wl_display_cancel_read() or - * wl_display_read_events(), usually after waiting for the - * display fd to become ready for reading, to release the lock. + * This function (or wl_display_prepare_read()) must be called before reading + * from the file descriptor using wl_display_read_events(). Calling + * wl_display_prepare_read_queue() announces the calling thread's intention to + * read and ensures that until the thread is ready to read and calls + * wl_display_read_events(), no other thread will read from the file descriptor. + * This only succeeds if the event queue is empty, and if not -1 is returned and + * errno set to EAGAIN. * - * \sa wl_display_prepare_read - * \memberof wl_event_queue + * If a thread successfully calls wl_display_prepare_read_queue(), it must + * either call wl_display_read_events() when it's ready or cancel the read + * intention by calling wl_display_cancel_read(). + * + * Use this function before polling on the display fd or integrate the fd into a + * toolkit event loop in a race-free way. A correct usage would be (with most + * error checking left out): + * + * \code + * while (wl_display_prepare_read_queue(display, queue) != 0) + * wl_display_dispatch_queue_pending(display, queue); + * wl_display_flush(display); + * + * ret = poll(fds, nfds, -1); + * if (has_error(ret)) + * wl_display_cancel_read(display); + * else + * wl_display_read_events(display); + * + * wl_display_dispatch_queue_pending(display, queue); + * \endcode + * + * Here we call wl_display_prepare_read_queue(), which ensures that between + * returning from that call and eventually calling wl_display_read_events(), no + * other thread will read from the fd and queue events in our queue. If the call + * to wl_display_prepare_read_queue() fails, we dispatch the pending events and + * try again until we're successful. + * + * When using wl_display_dispatch() we'd have something like: + * + * \code + * wl_display_dispatch_pending(display); + * wl_display_flush(display); + * poll(fds, nfds, -1); + * wl_display_dispatch(display); + * \endcode + * + * This sequence in not thread-safe. The race is immediately after poll(), + * where one thread could preempt and read events before the other thread calls + * wl_display_dispatch(). This call now blocks and starves the other + * fds in the event loop. + * + * Another race would be when using more event queues. + * When one thread calls wl_display_dispatch(_queue)(), then it + * reads all events from display's fd and queues them in appropriate + * queues. Then it dispatches only its own queue and the other events + * are sitting in their queues, waiting for dispatching. If that happens + * before the other thread managed to call poll(), it will + * block with events queued. + * + * The wl_display_prepare_read_queue() function doesn't acquire exclusive access + * to the display's fd. It only registers that the thread calling this function + * has intention to read from fd. When all registered readers call + * wl_display_read_events(), only one (at random) eventually reads and queues + * the events and the others are sleeping meanwhile. This way we avoid races and + * still can read from more threads. + * + * \sa wl_display_cancel_read(), wl_display_read_events(), + * wl_display_prepare_read() + * + * \memberof wl_display */ WL_EXPORT int wl_display_prepare_read_queue(struct wl_display *display, @@ -1410,80 +1471,11 @@ wl_display_prepare_read_queue(struct wl_display *display, * \param display The display context object * \return 0 on success or -1 if event queue was not empty * - * This function must be called before reading from the file - * descriptor using wl_display_read_events(). Calling - * wl_display_prepare_read() announces the calling thread's intention - * to read and ensures that until the thread is ready to read and - * calls wl_display_read_events(), no other thread will read from the - * file descriptor. This only succeeds if the event queue is empty - * though, and if there are undispatched events in the queue, -1 is - * returned and errno set to EAGAIN. + * This function does the same thing as wl_display_prepare_read_queue() + * with the default queue passed as the queue. * - * If a thread successfully calls wl_display_prepare_read(), it must - * either call wl_display_read_events() when it's ready or cancel the - * read intention by calling wl_display_cancel_read(). - * - * Use this function before polling on the display fd or to integrate - * the fd into a toolkit event loop in a race-free way. - * A correct usage would be (we left out most of error checking): - * - * \code - * while (wl_display_prepare_read(display) != 0) - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * - * ret = poll(fds, nfds, -1); - * if (has_error(ret)) - * wl_display_cancel_read(display); - * else - * wl_display_read_events(display); - * - * wl_display_dispatch_pending(display); - * \endcode - * - * Here we call wl_display_prepare_read(), which ensures that between - * returning from that call and eventually calling - * wl_display_read_events(), no other thread will read from the fd and - * queue events in our queue. If the call to wl_display_prepare_read() fails, - * we dispatch the pending events and try again until we're successful. - * - * When using wl_display_dispatch() we'd have something like: - * - * \code - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * poll(fds, nfds, -1); - * wl_display_dispatch(display); - * \endcode - * - * This sequence in not thread-safe. The race is immediately after poll(), - * where one thread could preempt and read events before the other thread calls - * wl_display_dispatch(). This call now blocks and starves the other - * fds in the event loop. - * - * Another race would be when using more event queues. - * When one thread calls wl_display_dispatch(_queue)(), then it - * reads all events from display's fd and queues them in appropriate - * queues. Then it dispatches only its own queue and the other events - * are sitting in their queues, waiting for dispatching. If that happens - * before the other thread managed to call poll(), it will - * block with events queued. - * - * wl_display_prepare_read() function doesn't acquire exclusive access - * to the display's fd. It only registers that the thread calling this function - * has intention to read from fd. - * When all registered readers call wl_display_read_events(), - * only one (at random) eventually reads and queues the events and the - * others are sleeping meanwhile. This way we avoid races and still - * can read from more threads. - * - * If the relevant queue is not the default queue, then - * wl_display_prepare_read_queue() and wl_display_dispatch_queue_pending() - * need to be used instead. - * - * \sa wl_display_cancel_read(), wl_display_read_events() - * - * \memberof wl_display + * \sa wl_display_prepare_read_queue + * \memberof wl_event_queue */ WL_EXPORT int wl_display_prepare_read(struct wl_display *display) From 9ebdcab1096acacffc3509888219d28a4c28a57d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 8 Oct 2015 11:00:54 +0800 Subject: [PATCH 0202/1152] scanner: Generate 'since' macros for requests as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already generate WL_[INTERFACE]_[REQUEST]_SINCE_VERSION macros for events in the server protocol headers. Lets do the same for requests in the client protocol headers as well. Signed-off-by: Jonas Ådahl Reviewed-by: David FORT Reviewed-by: Daniel Stone --- src/scanner.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scanner.c b/src/scanner.c index 5504fcec..f456aa50 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1270,6 +1270,7 @@ emit_header(struct protocol *protocol, enum side side) } else { emit_structs(&i->event_list, i, side); emit_opcodes(&i->request_list, i); + emit_opcode_versions(&i->request_list, i); emit_stubs(&i->request_list, i); } From 06fb8bd371403d43bc192577abd6b0a0c8b29c59 Mon Sep 17 00:00:00 2001 From: Auke Booij Date: Thu, 8 Oct 2015 14:35:34 +0100 Subject: [PATCH 0203/1152] Remove protocol/wayland.dtd The wayland scanner defines the protocol. The DTD specification is not used. Reviewed-by: Pekka Paalanen Reviewed-by: Nils Christopher Brause --- Makefile.am | 4 ++-- protocol/wayland.dtd | 29 ----------------------------- 2 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 protocol/wayland.dtd diff --git a/Makefile.am b/Makefile.am index 9114d982..4c57ecf8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,8 +16,8 @@ dist_aclocal_DATA = wayland-scanner.m4 dist_pkgdata_DATA = \ wayland-scanner.mk \ - protocol/wayland.xml \ - protocol/wayland.dtd + protocol/wayland.xml + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd deleted file mode 100644 index b8b15731..00000000 --- a/protocol/wayland.dtd +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From eba83cd5e1645986768fcd918c2f5cd76ba54f01 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 19 Oct 2015 20:54:49 -0500 Subject: [PATCH 0204/1152] shm: Add shm_buffer ref and shm_pool unref functions Sometimes the compositor wants to make sure a shm pool doesn't disappear out from under it. For example, in Enlightenment, rendering happens in a separate thread while the main thread can still dispatch events. If a client is destroyed during rendering, all its resources are cleaned up and its shm pools are unmapped. This causes the rendering thread to segfault. This patch adds a way for the compositor to increment the refcount of the shm pool so it can't disappear, and decrement it when it's finished. The ref/unref are asymmetrical (ref returns the pool) because it's possible the buffer itself will be gone when you need to unref the pool. Reviewed-by: Pekka Paalanen Signed-off-by: Derek Foreman --- src/wayland-server-core.h | 7 +++++++ src/wayland-shm.c | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index e605432c..4c2bdfe3 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -362,6 +362,7 @@ wl_resource_get_destroy_listener(struct wl_resource *resource, resource = tmp, \ tmp = wl_resource_from_link(wl_resource_get_link(resource)->next)) +struct wl_shm_pool; struct wl_shm_buffer; void @@ -388,6 +389,12 @@ wl_shm_buffer_get_width(struct wl_shm_buffer *buffer); int32_t wl_shm_buffer_get_height(struct wl_shm_buffer *buffer); +struct wl_shm_pool * +wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer); + +void +wl_shm_pool_unref(struct wl_shm_pool *pool); + int wl_display_init_shm(struct wl_display *display); diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 5c419fac..1ab8f893 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -412,6 +412,48 @@ wl_shm_buffer_get_height(struct wl_shm_buffer *buffer) return buffer->height; } +/** Get a reference to a shm_buffer's shm_pool + * + * \param buffer The buffer object + * + * Returns a pointer to a buffer's shm_pool and increases the + * shm_pool refcount. + * + * The compositor must remember to call wl_shm_pool_unref when + * it no longer needs the reference to ensure proper destruction + * of the pool. + * + * \memberof wl_shm_buffer + * \sa wl_shm_pool_unref + */ +WL_EXPORT struct wl_shm_pool * +wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) +{ + assert(buffer->pool->refcount); + + buffer->pool->refcount++; + return buffer->pool; +} + +/** Unreference a shm_pool + * + * \param buffer The pool object + * + * Drops a reference to a wl_shm_pool object. + * + * This is only necessary if the compositor has explicitly + * taken a reference with wl_shm_buffer_ref_pool(), otherwise + * the pool will be automatically destroyed when appropriate. + * + * \memberof wl_shm_pool + * \sa wl_shm_buffer_ref_pool + */ +WL_EXPORT void +wl_shm_pool_unref(struct wl_shm_pool *pool) +{ + shm_pool_unref(pool); +} + static void reraise_sigbus(void) { From 9a170b98342c1fde42cd3f7fbef73d5af86c3a7c Mon Sep 17 00:00:00 2001 From: Jon Cruz Date: Mon, 26 Oct 2015 14:51:19 +0900 Subject: [PATCH 0205/1152] cosmetic: fix inconsistent code style with header prototypes. A few of the header files had function prototypes that were not following project conventions, sometimes even in the same file. Corrected these to follow as per wayland-os.h. Signed-off-by: Jon A. Cruz --- src/wayland-client-core.h | 152 +++++++++++++++++++++--------- src/wayland-private.h | 81 +++++++++++----- src/wayland-server-core.h | 190 ++++++++++++++++++++++++++------------ src/wayland-util.h | 45 ++++++--- 4 files changed, 328 insertions(+), 140 deletions(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index dea70d9c..8b4b4b84 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -118,63 +118,123 @@ struct wl_display; */ struct wl_event_queue; -void wl_event_queue_destroy(struct wl_event_queue *queue); +void +wl_event_queue_destroy(struct wl_event_queue *queue); + +void +wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); + +void +wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode, + union wl_argument *args); + +struct wl_proxy * +wl_proxy_create(struct wl_proxy *factory, + const struct wl_interface *interface); + +struct wl_proxy * +wl_proxy_marshal_constructor(struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface, + ...); -void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); -void wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode, - union wl_argument *args); -struct wl_proxy *wl_proxy_create(struct wl_proxy *factory, - const struct wl_interface *interface); -struct wl_proxy *wl_proxy_marshal_constructor(struct wl_proxy *proxy, - uint32_t opcode, - const struct wl_interface *interface, - ...); struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface); -void wl_proxy_destroy(struct wl_proxy *proxy); -int wl_proxy_add_listener(struct wl_proxy *proxy, - void (**implementation)(void), void *data); -const void *wl_proxy_get_listener(struct wl_proxy *proxy); -int wl_proxy_add_dispatcher(struct wl_proxy *proxy, - wl_dispatcher_func_t dispatcher_func, - const void * dispatcher_data, void *data); -void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); -void *wl_proxy_get_user_data(struct wl_proxy *proxy); -uint32_t wl_proxy_get_id(struct wl_proxy *proxy); -const char *wl_proxy_get_class(struct wl_proxy *proxy); -void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); +void +wl_proxy_destroy(struct wl_proxy *proxy); -struct wl_display *wl_display_connect(const char *name); -struct wl_display *wl_display_connect_to_fd(int fd); -void wl_display_disconnect(struct wl_display *display); -int wl_display_get_fd(struct wl_display *display); -int wl_display_dispatch(struct wl_display *display); -int wl_display_dispatch_queue(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_dispatch_queue_pending(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_dispatch_pending(struct wl_display *display); -int wl_display_get_error(struct wl_display *display); -uint32_t wl_display_get_protocol_error(struct wl_display *display, - const struct wl_interface **interface, - uint32_t *id); +int +wl_proxy_add_listener(struct wl_proxy *proxy, + void (**implementation)(void), void *data); -int wl_display_flush(struct wl_display *display); -int wl_display_roundtrip_queue(struct wl_display *display, - struct wl_event_queue *queue); -int wl_display_roundtrip(struct wl_display *display); -struct wl_event_queue *wl_display_create_queue(struct wl_display *display); +const void * +wl_proxy_get_listener(struct wl_proxy *proxy); -int wl_display_prepare_read_queue(struct wl_display *display, +int +wl_proxy_add_dispatcher(struct wl_proxy *proxy, + wl_dispatcher_func_t dispatcher_func, + const void * dispatcher_data, void *data); + +void +wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); + +void * +wl_proxy_get_user_data(struct wl_proxy *proxy); + +uint32_t +wl_proxy_get_id(struct wl_proxy *proxy); + +const char * +wl_proxy_get_class(struct wl_proxy *proxy); + +void +wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); + +struct wl_display * +wl_display_connect(const char *name); + +struct wl_display * +wl_display_connect_to_fd(int fd); + +void +wl_display_disconnect(struct wl_display *display); + +int +wl_display_get_fd(struct wl_display *display); + +int +wl_display_dispatch(struct wl_display *display); + +int +wl_display_dispatch_queue(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_dispatch_queue_pending(struct wl_display *display, struct wl_event_queue *queue); -int wl_display_prepare_read(struct wl_display *display); -void wl_display_cancel_read(struct wl_display *display); -int wl_display_read_events(struct wl_display *display); -void wl_log_set_handler_client(wl_log_func_t handler); +int +wl_display_dispatch_pending(struct wl_display *display); + +int +wl_display_get_error(struct wl_display *display); + +uint32_t +wl_display_get_protocol_error(struct wl_display *display, + const struct wl_interface **interface, + uint32_t *id); + +int +wl_display_flush(struct wl_display *display); + +int +wl_display_roundtrip_queue(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_roundtrip(struct wl_display *display); + +struct wl_event_queue * +wl_display_create_queue(struct wl_display *display); + +int +wl_display_prepare_read_queue(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_prepare_read(struct wl_display *display); + +void +wl_display_cancel_read(struct wl_display *display); + +int +wl_display_read_events(struct wl_display *display); + +void +wl_log_set_handler_client(wl_log_func_t handler); #ifdef __cplusplus } diff --git a/src/wayland-private.h b/src/wayland-private.h index 17c507cd..da9040a6 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -71,34 +71,66 @@ struct wl_map { typedef void (*wl_iterator_func_t)(void *element, void *data); -void wl_map_init(struct wl_map *map, uint32_t side); -void wl_map_release(struct wl_map *map); -uint32_t wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data); -int wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data); -int wl_map_reserve_new(struct wl_map *map, uint32_t i); -void wl_map_remove(struct wl_map *map, uint32_t i); -void *wl_map_lookup(struct wl_map *map, uint32_t i); -uint32_t wl_map_lookup_flags(struct wl_map *map, uint32_t i); -void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data); +void +wl_map_init(struct wl_map *map, uint32_t side); + +void +wl_map_release(struct wl_map *map); + +uint32_t +wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data); + +int +wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data); + +int +wl_map_reserve_new(struct wl_map *map, uint32_t i); + +void +wl_map_remove(struct wl_map *map, uint32_t i); + +void * +wl_map_lookup(struct wl_map *map, uint32_t i); + +uint32_t +wl_map_lookup_flags(struct wl_map *map, uint32_t i); + +void +wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data); struct wl_connection; struct wl_closure; struct wl_proxy; -int wl_interface_equal(const struct wl_interface *iface1, - const struct wl_interface *iface2); +int +wl_interface_equal(const struct wl_interface *iface1, + const struct wl_interface *iface2); -struct wl_connection *wl_connection_create(int fd); -int wl_connection_destroy(struct wl_connection *connection); -void wl_connection_copy(struct wl_connection *connection, void *data, size_t size); -void wl_connection_consume(struct wl_connection *connection, size_t size); +struct wl_connection * +wl_connection_create(int fd); -int wl_connection_flush(struct wl_connection *connection); -int wl_connection_read(struct wl_connection *connection); +int +wl_connection_destroy(struct wl_connection *connection); -int wl_connection_write(struct wl_connection *connection, const void *data, size_t count); -int wl_connection_queue(struct wl_connection *connection, - const void *data, size_t count); +void +wl_connection_copy(struct wl_connection *connection, void *data, size_t size); + +void +wl_connection_consume(struct wl_connection *connection, size_t size); + +int +wl_connection_flush(struct wl_connection *connection); + +int +wl_connection_read(struct wl_connection *connection); + +int +wl_connection_write(struct wl_connection *connection, + const void *data, size_t count); + +int +wl_connection_queue(struct wl_connection *connection, + const void *data, size_t count); struct wl_closure { int count; @@ -133,6 +165,7 @@ struct wl_closure * wl_closure_marshal(struct wl_object *sender, uint32_t opcode, union wl_argument *args, const struct wl_message *message); + struct wl_closure * wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap, @@ -155,15 +188,21 @@ enum wl_closure_invoke_flag { void wl_closure_invoke(struct wl_closure *closure, uint32_t flags, struct wl_object *target, uint32_t opcode, void *data); + void wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher, struct wl_object *target, uint32_t opcode); + int wl_closure_send(struct wl_closure *closure, struct wl_connection *connection); + int wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); + void -wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send); +wl_closure_print(struct wl_closure *closure, + struct wl_object *target, int send); + void wl_closure_destroy(struct wl_closure *closure); diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 4c2bdfe3..55a2db08 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -49,34 +49,56 @@ typedef int (*wl_event_loop_timer_func_t)(void *data); typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data); typedef void (*wl_event_loop_idle_func_t)(void *data); -struct wl_event_loop *wl_event_loop_create(void); -void wl_event_loop_destroy(struct wl_event_loop *loop); -struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop, - int fd, uint32_t mask, - wl_event_loop_fd_func_t func, - void *data); -int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask); -struct wl_event_source *wl_event_loop_add_timer(struct wl_event_loop *loop, - wl_event_loop_timer_func_t func, - void *data); +struct wl_event_loop * +wl_event_loop_create(void); + +void +wl_event_loop_destroy(struct wl_event_loop *loop); + +struct wl_event_source * +wl_event_loop_add_fd(struct wl_event_loop *loop, + int fd, uint32_t mask, + wl_event_loop_fd_func_t func, + void *data); + +int +wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask); + +struct wl_event_source * +wl_event_loop_add_timer(struct wl_event_loop *loop, + wl_event_loop_timer_func_t func, + void *data); + struct wl_event_source * wl_event_loop_add_signal(struct wl_event_loop *loop, int signal_number, wl_event_loop_signal_func_t func, void *data); -int wl_event_source_timer_update(struct wl_event_source *source, - int ms_delay); -int wl_event_source_remove(struct wl_event_source *source); -void wl_event_source_check(struct wl_event_source *source); +int +wl_event_source_timer_update(struct wl_event_source *source, + int ms_delay); + +int +wl_event_source_remove(struct wl_event_source *source); + +void +wl_event_source_check(struct wl_event_source *source); -int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout); -void wl_event_loop_dispatch_idle(struct wl_event_loop *loop); -struct wl_event_source *wl_event_loop_add_idle(struct wl_event_loop *loop, - wl_event_loop_idle_func_t func, - void *data); -int wl_event_loop_get_fd(struct wl_event_loop *loop); +int +wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout); + +void +wl_event_loop_dispatch_idle(struct wl_event_loop *loop); + +struct wl_event_source * +wl_event_loop_add_idle(struct wl_event_loop *loop, + wl_event_loop_idle_func_t func, + void *data); + +int +wl_event_loop_get_fd(struct wl_event_loop *loop); struct wl_client; struct wl_display; @@ -85,51 +107,89 @@ struct wl_resource; struct wl_global; typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data); -void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, - struct wl_listener * listener); -struct wl_listener *wl_event_loop_get_destroy_listener( - struct wl_event_loop *loop, - wl_notify_func_t notify); +void +wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, + struct wl_listener * listener); -struct wl_display *wl_display_create(void); -void wl_display_destroy(struct wl_display *display); -struct wl_event_loop *wl_display_get_event_loop(struct wl_display *display); -int wl_display_add_socket(struct wl_display *display, const char *name); -const char *wl_display_add_socket_auto(struct wl_display *display); -void wl_display_terminate(struct wl_display *display); -void wl_display_run(struct wl_display *display); -void wl_display_flush_clients(struct wl_display *display); +struct wl_listener * +wl_event_loop_get_destroy_listener( + struct wl_event_loop *loop, + wl_notify_func_t notify); + +struct wl_display * +wl_display_create(void); + +void +wl_display_destroy(struct wl_display *display); + +struct wl_event_loop * +wl_display_get_event_loop(struct wl_display *display); + +int +wl_display_add_socket(struct wl_display *display, const char *name); + +const char * +wl_display_add_socket_auto(struct wl_display *display); + +void +wl_display_terminate(struct wl_display *display); + +void +wl_display_run(struct wl_display *display); + +void +wl_display_flush_clients(struct wl_display *display); typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, uint32_t version, uint32_t id); -uint32_t wl_display_get_serial(struct wl_display *display); -uint32_t wl_display_next_serial(struct wl_display *display); +uint32_t +wl_display_get_serial(struct wl_display *display); -void wl_display_add_destroy_listener(struct wl_display *display, - struct wl_listener *listener); -struct wl_listener *wl_display_get_destroy_listener(struct wl_display *display, - wl_notify_func_t notify); +uint32_t +wl_display_next_serial(struct wl_display *display); -struct wl_global *wl_global_create(struct wl_display *display, - const struct wl_interface *interface, - int version, - void *data, wl_global_bind_func_t bind); -void wl_global_destroy(struct wl_global *global); +void +wl_display_add_destroy_listener(struct wl_display *display, + struct wl_listener *listener); -struct wl_client *wl_client_create(struct wl_display *display, int fd); -void wl_client_destroy(struct wl_client *client); -void wl_client_flush(struct wl_client *client); -void wl_client_get_credentials(struct wl_client *client, - pid_t *pid, uid_t *uid, gid_t *gid); +struct wl_listener * +wl_display_get_destroy_listener(struct wl_display *display, + wl_notify_func_t notify); -void wl_client_add_destroy_listener(struct wl_client *client, - struct wl_listener *listener); -struct wl_listener *wl_client_get_destroy_listener(struct wl_client *client, - wl_notify_func_t notify); +struct wl_global * +wl_global_create(struct wl_display *display, + const struct wl_interface *interface, + int version, + void *data, wl_global_bind_func_t bind); + +void +wl_global_destroy(struct wl_global *global); + +struct wl_client * +wl_client_create(struct wl_display *display, int fd); + +void +wl_client_destroy(struct wl_client *client); + +void +wl_client_flush(struct wl_client *client); + +void +wl_client_get_credentials(struct wl_client *client, + pid_t *pid, uid_t *uid, gid_t *gid); + +void +wl_client_add_destroy_listener(struct wl_client *client, + struct wl_listener *listener); + +struct wl_listener * +wl_client_get_destroy_listener(struct wl_client *client, + wl_notify_func_t notify); struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id); + void wl_client_post_no_memory(struct wl_client *client); @@ -282,19 +342,27 @@ typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource); * - type=new_id: (struct wl_object *) or (struct wl_resource *) * - type=object: (struct wl_object *) or (struct wl_resource *) */ -void wl_resource_post_event(struct wl_resource *resource, - uint32_t opcode, ...); -void wl_resource_post_event_array(struct wl_resource *resource, - uint32_t opcode, union wl_argument *args); -void wl_resource_queue_event(struct wl_resource *resource, - uint32_t opcode, ...); +void +wl_resource_post_event(struct wl_resource *resource, + uint32_t opcode, ...); + +void +wl_resource_post_event_array(struct wl_resource *resource, + uint32_t opcode, union wl_argument *args); + +void +wl_resource_queue_event(struct wl_resource *resource, + uint32_t opcode, ...); + void wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args); /* msg is a printf format string, variable args are its args. */ -void wl_resource_post_error(struct wl_resource *resource, - uint32_t code, const char *msg, ...) +void +wl_resource_post_error(struct wl_resource *resource, + uint32_t code, const char *msg, ...) __attribute__ ((format (printf, 3, 4))); + void wl_resource_post_no_memory(struct wl_resource *resource); struct wl_display * diff --git a/src/wayland-util.h b/src/wayland-util.h index 3d04bdd0..35b50ea7 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -121,12 +121,23 @@ struct wl_list { struct wl_list *next; }; -void wl_list_init(struct wl_list *list); -void wl_list_insert(struct wl_list *list, struct wl_list *elm); -void wl_list_remove(struct wl_list *elm); -int wl_list_length(const struct wl_list *list); -int wl_list_empty(const struct wl_list *list); -void wl_list_insert_list(struct wl_list *list, struct wl_list *other); +void +wl_list_init(struct wl_list *list); + +void +wl_list_insert(struct wl_list *list, struct wl_list *elm); + +void +wl_list_remove(struct wl_list *elm); + +int +wl_list_length(const struct wl_list *list); + +int +wl_list_empty(const struct wl_list *list); + +void +wl_list_insert_list(struct wl_list *list, struct wl_list *other); /** * Retrieves a pointer to the containing struct of a given member item. @@ -206,10 +217,17 @@ struct wl_array { (const char *) pos < ((const char *) (array)->data + (array)->size); \ (pos)++) -void wl_array_init(struct wl_array *array); -void wl_array_release(struct wl_array *array); -void *wl_array_add(struct wl_array *array, size_t size); -int wl_array_copy(struct wl_array *array, struct wl_array *source); +void +wl_array_init(struct wl_array *array); + +void +wl_array_release(struct wl_array *array); + +void * +wl_array_add(struct wl_array *array, size_t size); + +int +wl_array_copy(struct wl_array *array, struct wl_array *source); typedef int32_t wl_fixed_t; @@ -239,11 +257,14 @@ wl_fixed_from_double(double d) return u.i; } -static inline int wl_fixed_to_int(wl_fixed_t f) +static inline int +wl_fixed_to_int(wl_fixed_t f) { return f / 256; } -static inline wl_fixed_t wl_fixed_from_int(int i) + +static inline wl_fixed_t +wl_fixed_from_int(int i) { return i * 256; } From 1cf175eba453c4453b6be5081afc10cd515590a8 Mon Sep 17 00:00:00 2001 From: Jon Cruz Date: Mon, 26 Oct 2015 11:50:32 +0900 Subject: [PATCH 0206/1152] scanner: stop adding trailing whitespace to copyright Generated code was unconditionally adding a space to lines in comments for copyright blocks even if the line was blank. Updated to not add trailing whitespace for blank lines. Signed-off-by: Jon A. Cruz --- src/scanner.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index f456aa50..b231d022 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1141,8 +1141,9 @@ format_copyright(const char *copyright) } if (copyright[i] == '\n' || copyright[i] == '\0') { - printf("%s %.*s\n", + printf("%s%s%.*s\n", i == 0 ? "/*" : " *", + i > start ? " " : "", i - start, copyright + start); bol = 1; } From f150d7aec26d2d6f0f878f49edcca66b89265111 Mon Sep 17 00:00:00 2001 From: Jon Cruz Date: Wed, 28 Oct 2015 12:03:37 +0900 Subject: [PATCH 0207/1152] cosmetic: fix incorrect whitespace. Fixed instance where spaces were used instead of tabs. Changes since v1: * rebased Signed-off-by: Jon A. Cruz --- src/wayland-server-core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 55a2db08..73f2dd28 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -333,7 +333,7 @@ typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource); * parameters, in the order they appear in the protocol XML specification. * * The variable arguments' types are: - * - type=uint: uint32_t + * - type=uint: uint32_t * - type=int: int32_t * - type=fixed: wl_fixed_t * - type=string: (const char *) to a nil-terminated string From 999225c17a6ee23d5b5171b80b5158f93beb7abc Mon Sep 17 00:00:00 2001 From: Auke Booij Date: Mon, 26 Oct 2015 12:16:31 +0000 Subject: [PATCH 0208/1152] doc: document the enum and bitfield attributes Introduce the enum and bitfield attributes, which allow you to refer to the enum you are expecting in an argument, and specify which enums are to be thought of as bitfields. Changes since v3: - Fix typo ("description" -> "descriptive") Signed-off-by: Auke Booij Reviewed-by: Nils Chr. Brause Reviewed-by: Bryce Harrington --- doc/publican/sources/Protocol.xml | 41 ++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 477063be..66cebfb6 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -14,6 +14,38 @@ object implements an interface and the requests include an opcode that identifies which method in the interface to invoke. + + The protocol is message-based. A message sent by a client to the server + is called request. A message from the server to a client is called event. + A message has a number of arguments, each of which has a certain type (see + for a list of argument types). + + + Additionally, the protocol can specify enums which associate + names to specific numeric enumeration values. These are primarily just + descriptive in nature: at the wire format level enums are just integers. + But they also serve a secondary purpose to enhance type safety or + otherwise add context for use in language bindings or other such code. + This latter usage is only supported so long as code written before these + attributes were introduced still works after; in other words, adding an + enum should not break API, otherwise it puts backwards compatibility at + risk. + + + enums can be defined as just a set of integers, or as + bitfields. This is specified via the bitfield boolean + attribute in the enum definition. If this attribute is true, + the enum is intended to be accessed primarily using bitwise operations, + for example when arbitrarily many choices of the enum can be ORed + together; if it is false, or the attribute is omitted, then the enum + arguments are a just a sequence of numerical values. + + + The enum attribute can be used on either uint + or int arguments, however if the enum is + defined as a bitfield, it can only be used on + uint args. + The server sends back events to the client, each event is emitted from an object. Events can be error conditions. The event includes the @@ -62,14 +94,11 @@ The protocol is sent over a UNIX domain stream socket, where the endpoint usually is named wayland-0 (although it can be changed via WAYLAND_DISPLAY - in the environment). The protocol is message-based. A - message sent by a client to the server is called request. A message - from the server to a client is called event. Every message is - structured as 32-bit words, values are represented in the host's - byte-order. + in the environment). - The message header has 2 words in it: + Every message is structured as 32-bit words; values are represented in the + host's byte-order. The message header has 2 words in it: From 851614fa78862499e016c5718e730fefbb8e3b73 Mon Sep 17 00:00:00 2001 From: Auke Booij Date: Sat, 24 Oct 2015 12:07:48 +0100 Subject: [PATCH 0209/1152] protocol: specify enum and bitfield attributes Signed-off-by: Auke Booij Reviewed-by: Nils Chr. Brause Reviewed-by: Bryce Harrington Acked-by: Victor Berger --- protocol/wayland.xml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 59819e9a..9c22d45e 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -367,7 +367,7 @@ can be used for buffers. Known formats include argb8888 and xrgb8888. - + @@ -746,7 +746,7 @@ - + These values are used to indicate which edge of a surface is being dragged in a resize operation. The server may @@ -774,7 +774,7 @@ - + @@ -785,7 +785,7 @@ - + These flags specify details of the expected behaviour of transient surfaces. Used in the set_transient request. @@ -807,7 +807,7 @@ - + @@ -858,7 +858,7 @@ with the dimensions for the output on which the surface will be made fullscreen. - + @@ -891,7 +891,7 @@ - + @@ -972,7 +972,7 @@ in surface local coordinates. - + @@ -1337,7 +1337,7 @@ maintains a keyboard focus and a pointer focus. - + This is a bitmask of capabilities this seat has; if a member is set, then it is present on the seat. @@ -1353,7 +1353,7 @@ keyboard or touch capabilities. The argument is a capability enum containing the complete set of capabilities this seat has. - + @@ -1530,7 +1530,7 @@ - + @@ -1562,7 +1562,7 @@ - + @@ -1602,7 +1602,7 @@ This event provides a file descriptor to the client which can be memory-mapped to provide a keyboard mapping description. - + @@ -1647,7 +1647,7 @@ - + @@ -1828,17 +1828,17 @@ summary="width in millimeters of the output"/> - - - + These flags describe properties of an output mode. They are used in the flags bitfield of the mode event. @@ -1865,7 +1865,7 @@ the output may be scaled, as described in wl_output.scale, or transformed , as described in wl_output.transform. - + From 1771299a5a965c1f95c18ef795c29db876133a81 Mon Sep 17 00:00:00 2001 From: Auke Booij Date: Mon, 26 Oct 2015 19:39:52 +0000 Subject: [PATCH 0210/1152] scanner: enforce correct argument type for enums The scanner now checks whether arguments that have an associated have the right type. An argument with an enum attribute must be of type int or uint, and if the with that name has the bitfield attribute set to true, then the argument must be of type uint. Changes since v3: - Remove useless allow_null check - Switch to using bool - Clearer message on errorous input - Minor formatting fix Signed-off-by: Auke Booij Reviewed-by: Bryce Harrington Reviewed-by: Nils Chr. Brause --- src/scanner.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index b231d022..8ecdd56e 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -128,6 +128,7 @@ struct arg { char *interface_name; struct wl_list link; char *summary; + char *enumeration_name; }; struct enumeration { @@ -136,6 +137,7 @@ struct enumeration { struct wl_list entry_list; struct wl_list link; struct description *description; + bool bitfield; }; struct entry { @@ -540,6 +542,8 @@ start_element(void *data, const char *element_name, const char **atts) const char *summary = NULL; const char *since = NULL; const char *allow_null = NULL; + const char *enumeration_name = NULL; + const char *bitfield = NULL; int i, version = 0; ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); @@ -562,6 +566,10 @@ start_element(void *data, const char *element_name, const char **atts) since = atts[i + 1]; if (strcmp(atts[i], "allow-null") == 0) allow_null = atts[i + 1]; + if (strcmp(atts[i], "enum") == 0) + enumeration_name = atts[i + 1]; + if (strcmp(atts[i], "bitfield") == 0) + bitfield = atts[i + 1]; } ctx->character_data_length = 0; @@ -655,6 +663,11 @@ start_element(void *data, const char *element_name, const char **atts) "allow-null is only valid for objects, strings, and arrays"); } + if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0) + arg->enumeration_name = NULL; + else + arg->enumeration_name = xstrdup(enumeration_name); + if (summary) arg->summary = xstrdup(summary); @@ -665,6 +678,16 @@ start_element(void *data, const char *element_name, const char **atts) fail(&ctx->loc, "no enum name given"); enumeration = create_enumeration(name); + + if (bitfield == NULL || strcmp(bitfield, "false") == 0) + enumeration->bitfield = false; + else if (strcmp(bitfield, "true") == 0) + enumeration->bitfield = true; + else + fail(&ctx->loc, + "invalid value (%s) for bitfield attribute (only true/false are accepted)", + bitfield); + wl_list_insert(ctx->interface->enumeration_list.prev, &enumeration->link); @@ -700,6 +723,46 @@ start_element(void *data, const char *element_name, const char **atts) } } +static void +verify_arguments(struct parse_context *ctx, struct wl_list *messages, struct wl_list *enumerations) +{ + struct message *m; + wl_list_for_each(m, messages, link) { + struct arg *a; + wl_list_for_each(a, &m->arg_list, link) { + struct enumeration *e, *f; + + if (!a->enumeration_name) + continue; + + f = NULL; + wl_list_for_each(e, enumerations, link) { + if(strcmp(e->name, a->enumeration_name) == 0) + f = e; + } + + if (f == NULL) + fail(&ctx->loc, + "could not find enumeration %s", + a->enumeration_name); + + switch (a->type) { + case INT: + if (f->bitfield) + fail(&ctx->loc, + "bitfield-style enum must only be referenced by uint"); + break; + case UNSIGNED: + break; + default: + fail(&ctx->loc, + "enumeration-style argument has wrong type"); + } + } + } + +} + static void end_element(void *data, const XML_Char *name) { @@ -723,6 +786,12 @@ end_element(void *data, const XML_Char *name) ctx->enumeration->name); } ctx->enumeration = NULL; + } else if (strcmp(name, "interface") == 0) { + struct interface *i = ctx->interface; + + verify_arguments(ctx, &i->request_list, &i->enumeration_list); + verify_arguments(ctx, &i->event_list, &i->enumeration_list); + } } From 4a97cb35794866414b84242a89d1dbcc7f9c59fe Mon Sep 17 00:00:00 2001 From: Auke Booij Date: Sat, 24 Oct 2015 12:07:50 +0100 Subject: [PATCH 0211/1152] doc: output enum and bitfield attributes in the documentation Signed-off-by: Auke Booij Reviewed-by: Nils Chr. Brause Reviewed-by: Bryce Harrington --- doc/publican/protocol-to-docbook.xsl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 7b45969e..fad207a8 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -102,6 +102,12 @@ + + + + + + - @@ -171,6 +177,9 @@
<xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> + <xsl:if test="@bitfield"> + - bitfield + </xsl:if> <xsl:if test="description/@summary"> - <xsl:value-of select="description/@summary" /> </xsl:if> From 91881e8f89262f18f7543a6fd5f440ea5c13ce30 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 5 Nov 2015 13:57:45 -0600 Subject: [PATCH 0212/1152] shm: Deprecate wl_shm_buffer_create() From irc: <pq> it creates a wl_buffer object in a way that no client can ever access the storage. So, let's replace it with return NULL; and mark it with attribute deprecated in the header. Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Giulio Camuffo <giuliocamuffo@gmail.com> --- src/wayland-server-core.h | 2 +- src/wayland-shm.c | 29 +---------------------------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 73f2dd28..85b4b9e6 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -472,7 +472,7 @@ wl_display_add_shm_format(struct wl_display *display, uint32_t format); struct wl_shm_buffer * wl_shm_buffer_create(struct wl_client *client, uint32_t id, int32_t width, int32_t height, - int32_t stride, uint32_t format); + int32_t stride, uint32_t format) WL_DEPRECATED; void wl_log_set_handler_server(wl_log_func_t handler); diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 1ab8f893..a05a8a06 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -319,34 +319,7 @@ wl_shm_buffer_create(struct wl_client *client, uint32_t id, int32_t width, int32_t height, int32_t stride, uint32_t format) { - struct wl_shm_buffer *buffer; - - if (!format_is_supported(client, format)) - return NULL; - - buffer = malloc(sizeof *buffer + stride * height); - if (buffer == NULL) - return NULL; - - buffer->width = width; - buffer->height = height; - buffer->format = format; - buffer->stride = stride; - buffer->offset = 0; - buffer->pool = NULL; - - buffer->resource = - wl_resource_create(client, &wl_buffer_interface, 1, id); - if (buffer->resource == NULL) { - free(buffer); - return NULL; - } - - wl_resource_set_implementation(buffer->resource, - &shm_buffer_interface, - buffer, destroy_buffer); - - return buffer; + return NULL; } WL_EXPORT struct wl_shm_buffer * From 2aee2069a04afebf839d63c89411f639247e780b Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 5 Nov 2015 13:57:46 -0600 Subject: [PATCH 0213/1152] shm: Move deprecated function to the bottom of the file In wayland-server.c we group the deprecated functions and disable doxygen for them. Do that here too. Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Giulio Camuffo <giuliocamuffo@gmail.com> --- src/wayland-shm.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index a05a8a06..db239095 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -314,14 +314,6 @@ wl_display_init_shm(struct wl_display *display) return 0; } -WL_EXPORT struct wl_shm_buffer * -wl_shm_buffer_create(struct wl_client *client, - uint32_t id, int32_t width, int32_t height, - int32_t stride, uint32_t format) -{ - return NULL; -} - WL_EXPORT struct wl_shm_buffer * wl_shm_buffer_get(struct wl_resource *resource) { @@ -588,3 +580,20 @@ wl_shm_buffer_end_access(struct wl_shm_buffer *buffer) sigbus_data->current_pool = NULL; } } + +/** \cond */ /* Deprecated functions below. */ + +WL_EXPORT struct wl_shm_buffer * +wl_shm_buffer_create(struct wl_client *client, + uint32_t id, int32_t width, int32_t height, + int32_t stride, uint32_t format) +{ + return NULL; +} + +/** \endcond */ + +/* Functions at the end of this file are deprecated. Instead of adding new + * code here, add it before the comment above that states: + * Deprecated functions below. + */ From 8bc42fbf7bb53f4942c50be10be572ee479bab0f Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 5 Nov 2015 13:57:47 -0600 Subject: [PATCH 0214/1152] shm: wl_shm_buffer_get_data() requires a valid pool. There's no situation where a shm buffer without a pool makes sense, so we enforce the pool's existence a little more rigidly. Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Giulio Camuffo <giuliocamuffo@gmail.com> --- src/wayland-shm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index db239095..0cd8c118 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -353,10 +353,12 @@ wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer) WL_EXPORT void * wl_shm_buffer_get_data(struct wl_shm_buffer *buffer) { - if (buffer->pool) - return buffer->pool->data + buffer->offset; - else - return buffer + 1; + assert(buffer->pool); + + if (!buffer->pool) + return NULL; + + return buffer->pool->data + buffer->offset; } WL_EXPORT uint32_t From 10d5f97706f6228b607daebb90166752beb8fc77 Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Mon, 16 Nov 2015 11:53:36 +0100 Subject: [PATCH 0215/1152] event-loop: remove extra header we don't use assert() anywhere in this file, so remove #include <assert.h> Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/event-loop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index 130c7beb..ea27b695 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -36,7 +36,6 @@ #include <sys/signalfd.h> #include <sys/timerfd.h> #include <unistd.h> -#include <assert.h> #include "wayland-private.h" #include "wayland-server.h" #include "wayland-os.h" From 5660ea414f9a2a81409074346bb6140342e02425 Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Fri, 6 Nov 2015 08:02:00 +1000 Subject: [PATCH 0216/1152] doc: make the doxygen output dependent on scanner.c When the scanner changes, we need to rebuild Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/doxygen/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 5520d396..a8bb95f8 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -44,14 +44,14 @@ $(diagrams): $(diagramssrc) $(diagram_maps): $(diagramssrc) -xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | xml/% +xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | xml/% $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/$*"; \ echo "INPUT= $(scanned_src_files_$*)"; \ ) | $(DOXYGEN) - -man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3 +man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | man/man3 $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_MAN=YES"; \ echo "MAN_OUTPUT=man"; \ From c7bada036db1b630bbd4de8a31914b521d3bcdd1 Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Mon, 16 Nov 2015 11:49:02 +0100 Subject: [PATCH 0217/1152] add wl_abort private function On many places in the code we use wl_log + abort or wl_log + assert(0). Replace these with one call to wl_abort, so that we don't mix abort(), assert(0) and we'll save few lines Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/connection.c | 22 +++++++--------------- src/wayland-client.c | 12 ++++-------- src/wayland-private.h | 1 + src/wayland-util.c | 12 ++++++++++++ tests/sanity-test.c | 7 ++++++- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/connection.c b/src/connection.c index b3d9bd45..6742f19c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -33,7 +33,6 @@ #include <stdio.h> #include <errno.h> #include <sys/uio.h> -#include <assert.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> @@ -569,16 +568,12 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, case 'h': fd = args[i].h; dup_fd = wl_os_dupfd_cloexec(fd, 0); - if (dup_fd < 0) { - wl_log("dup failed: %m"); - abort(); - } + if (dup_fd < 0) + wl_abort("dup failed: %s\n", strerror(errno)); closure->args[i].h = dup_fd; break; default: - wl_log("unhandled format code: '%c'\n", - arg.type); - assert(0); + wl_abort("unhandled format code: '%c'\n", arg.type); break; } } @@ -771,8 +766,7 @@ wl_connection_demarshal(struct wl_connection *connection, closure->args[i].h = fd; break; default: - wl_log("unknown type\n"); - assert(0); + wl_abort("unknown type\n"); break; } } @@ -906,8 +900,7 @@ convert_arguments_to_ffi(const char *signature, uint32_t flags, ffi_args[i] = &args[i].h; break; default: - wl_log("unknown type\n"); - assert(0); + wl_abort("unknown type\n"); break; } } @@ -938,9 +931,8 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags, implementation = target->implementation; if (!implementation[opcode]) { - wl_log("listener function for opcode %u of %s is NULL\n", - opcode, target->interface->name); - abort(); + wl_abort("listener function for opcode %u of %s is NULL\n", + opcode, target->interface->name); } ffi_call(&cif, implementation[opcode], NULL, ffi_args); } diff --git a/src/wayland-client.c b/src/wayland-client.c index b1c600f4..509be08c 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -597,18 +597,14 @@ wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, } closure = wl_closure_marshal(&proxy->object, opcode, args, message); - if (closure == NULL) { - wl_log("Error marshalling request: %m\n"); - abort(); - } + if (closure == NULL) + wl_abort("Error marshalling request: %s\n", strerror(errno)); if (debug_client) wl_closure_print(closure, &proxy->object, true); - if (wl_closure_send(closure, proxy->display->connection)) { - wl_log("Error sending request: %m\n"); - abort(); - } + if (wl_closure_send(closure, proxy->display->connection)) + wl_abort("Error sending request: %s\n", strerror(errno)); wl_closure_destroy(closure); diff --git a/src/wayland-private.h b/src/wayland-private.h index da9040a6..58ac952b 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -209,6 +209,7 @@ wl_closure_destroy(struct wl_closure *closure); extern wl_log_func_t wl_log_handler; void wl_log(const char *fmt, ...); +void wl_abort(const char *fmt, ...); struct wl_display; diff --git a/src/wayland-util.c b/src/wayland-util.c index 00265e9f..e782309f 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -385,3 +385,15 @@ wl_log(const char *fmt, ...) wl_log_handler(fmt, argp); va_end(argp); } + +void +wl_abort(const char *fmt, ...) +{ + va_list argp; + + va_start(argp, fmt); + wl_log_handler(fmt, argp); + va_end(argp); + + abort(); +} diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 3f589b56..65d986dc 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -31,8 +31,8 @@ #include "test-runner.h" #include "wayland-util.h" +#include "wayland-private.h" -#define WL_HIDE_DEPRECATED #include "test-compositor.h" extern int leak_check_enabled; @@ -56,6 +56,11 @@ FAIL_TEST(fail_abort) abort(); } +FAIL_TEST(fail_wl_abort) +{ + wl_abort("Abort the program\n"); +} + FAIL_TEST(fail_kill) { kill(getpid(), SIGTERM); From 9d794d9f7736ab7ae177aeb69d946f78a00363d2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Mon, 9 Nov 2015 14:14:59 +1000 Subject: [PATCH 0218/1152] Revert "Remove protocol/wayland.dtd" This reverts commit 06fb8bd371403d43bc192577abd6b0a0c8b29c59. Having a DTD hooked up gives an indication of what we expect the protocol to be, which is a clearer documentation than the current "whatever scanner.c manages to parse". Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- Makefile.am | 4 ++-- protocol/wayland.dtd | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 protocol/wayland.dtd diff --git a/Makefile.am b/Makefile.am index 4c57ecf8..9114d982 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,8 +16,8 @@ dist_aclocal_DATA = wayland-scanner.m4 dist_pkgdata_DATA = \ wayland-scanner.mk \ - protocol/wayland.xml - + protocol/wayland.xml \ + protocol/wayland.dtd pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd new file mode 100644 index 00000000..b8b15731 --- /dev/null +++ b/protocol/wayland.dtd @@ -0,0 +1,29 @@ +<!ELEMENT protocol (copyright?, interface+)> + <!ATTLIST protocol name CDATA #REQUIRED> +<!ELEMENT copyright (#PCDATA)> +<!ELEMENT interface (description?,(request|event|enum)+)> + <!ATTLIST interface name CDATA #REQUIRED> + <!ATTLIST interface version CDATA #REQUIRED> +<!ELEMENT request (description?,arg*)> + <!ATTLIST request name CDATA #REQUIRED> + <!ATTLIST request type CDATA #IMPLIED> + <!ATTLIST request since CDATA #IMPLIED> +<!ELEMENT event (description?,arg*)> + <!ATTLIST event name CDATA #REQUIRED> + <!ATTLIST event since CDATA #IMPLIED> +<!ELEMENT enum (description?,entry*)> + <!ATTLIST enum name CDATA #REQUIRED> + <!ATTLIST enum since CDATA #IMPLIED> +<!ELEMENT entry (description?)> + <!ATTLIST entry name CDATA #REQUIRED> + <!ATTLIST entry value CDATA #REQUIRED> + <!ATTLIST entry summary CDATA #IMPLIED> + <!ATTLIST entry since CDATA #IMPLIED> +<!ELEMENT arg (description?)> + <!ATTLIST arg name CDATA #REQUIRED> + <!ATTLIST arg type CDATA #REQUIRED> + <!ATTLIST arg summary CDATA #IMPLIED> + <!ATTLIST arg interface CDATA #IMPLIED> + <!ATTLIST arg allow-null CDATA #IMPLIED> +<!ELEMENT description (#PCDATA)> + <!ATTLIST description summary CDATA #REQUIRED> From 0e8619211476ec38610108850033f6aee21f1978 Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Mon, 9 Nov 2015 14:15:00 +1000 Subject: [PATCH 0219/1152] protocol: allow for a <description> element below <protocol> The scanner parses this already, it doesn't do anything with it though. The DTD requires the order to be copyright, description, then the interfaces. That's largely a DTD limitation, the scanner doesn't care. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- protocol/wayland.dtd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd index b8b15731..e28dbc08 100644 --- a/protocol/wayland.dtd +++ b/protocol/wayland.dtd @@ -1,4 +1,4 @@ -<!ELEMENT protocol (copyright?, interface+)> +<!ELEMENT protocol (copyright?, description?, interface+)> <!ATTLIST protocol name CDATA #REQUIRED> <!ELEMENT copyright (#PCDATA)> <!ELEMENT interface (description?,(request|event|enum)+)> From e65aed46168fc86a7e78db071472278ea533f526 Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Tue, 10 Nov 2015 09:34:32 +1000 Subject: [PATCH 0220/1152] protocol: add the new bitfields to the dtd See 851614fa78862499e016c5718e730fefbb8e3b73 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Auke Booij <auke@tulcod.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- protocol/wayland.dtd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd index e28dbc08..15f20ab6 100644 --- a/protocol/wayland.dtd +++ b/protocol/wayland.dtd @@ -14,6 +14,7 @@ <!ELEMENT enum (description?,entry*)> <!ATTLIST enum name CDATA #REQUIRED> <!ATTLIST enum since CDATA #IMPLIED> + <!ATTLIST enum bitfield CDATA #IMPLIED> <!ELEMENT entry (description?)> <!ATTLIST entry name CDATA #REQUIRED> <!ATTLIST entry value CDATA #REQUIRED> @@ -25,5 +26,6 @@ <!ATTLIST arg summary CDATA #IMPLIED> <!ATTLIST arg interface CDATA #IMPLIED> <!ATTLIST arg allow-null CDATA #IMPLIED> + <!ATTLIST arg enum CDATA #IMPLIED> <!ELEMENT description (#PCDATA)> <!ATTLIST description summary CDATA #REQUIRED> From f66e2d53dd8920451a4d9544b2fd2568a6a75b9b Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Tue, 10 Nov 2015 09:53:08 +1000 Subject: [PATCH 0221/1152] Validate the protocol xml during scanning Embed the wayland.dtd protocol data into the scanner binary so we can validate external protocol files without requiring makefile changes. Hat-tip to Pekka Paalanen for the embedding trick. The embedding trick doesn't work well if the to-be-embedded file is in a different location than the source file, so copy/link it during configure and then build it in from the local directory. The current expat parser is not a validating parser, moving scanner.c to another parser has the risk of breaking compatibility. This patch adds libxml2 as extra (optional) dependency, but that also requires parsing the input twice. If the protocol fails validation a warning is printed but no error is returned otherwise. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- Makefile.am | 11 +++++--- configure.ac | 13 ++++++++++ src/dtddata.S | 40 +++++++++++++++++++++++++++++ src/scanner.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 src/dtddata.S diff --git a/Makefile.am b/Makefile.am index 9114d982..7d31a392 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,11 +23,16 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = bin_PROGRAMS = wayland-scanner -wayland_scanner_SOURCES = src/scanner.c -wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS) -wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la +wayland_scanner_SOURCES = src/scanner.c src/dtddata.S +wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(LIBXML_CFLAGS) $(AM_CFLAGS) +wayland_scanner_LDADD = $(EXPAT_LIBS) $(LIBXML_LIBS) libwayland-util.la pkgconfig_DATA += src/wayland-scanner.pc +src/dtddata.o: protocol/wayland.dtd + +%.o: %.S + $(AM_V_GEN)$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c -o $@ $< + if USE_HOST_SCANNER wayland_scanner = wayland-scanner else diff --git a/configure.ac b/configure.ac index ef269294..48658cf8 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,7 @@ AM_SILENT_RULES([yes]) AC_PROG_CC AC_PROG_CXX AC_PROG_GREP +AM_PROG_AS # check if we have C++ compiler. This is hacky workaround, # for a reason why it is this way see @@ -71,6 +72,12 @@ AC_ARG_ENABLE([documentation], [], [enable_documentation=yes]) +AC_ARG_ENABLE([dtd-validation], + [AC_HELP_STRING([--disable-dtd-validation], + [Disable DTD validation of the protocol])], + [], + [enable_dtdvalidation=yes]) + AM_CONDITIONAL(USE_HOST_SCANNER, test "x$with_host_scanner" = xyes) AM_CONDITIONAL(ENABLE_LIBRARIES, test "x$enable_libraries" = xyes) @@ -105,6 +112,12 @@ PKG_CHECK_MODULES(EXPAT, [expat], [], AC_SUBST(EXPAT_LIBS) ]) +if test "x$enable_dtdvalidation" = "xyes"; then + PKG_CHECK_MODULES(LIBXML, [libxml-2.0]) + AC_DEFINE(HAVE_LIBXML, 1, [libxml-2.0 is available]) + AC_CONFIG_LINKS([src/wayland.dtd.embed:protocol/wayland.dtd]) +fi + AC_PATH_PROG(XSLTPROC, xsltproc) AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"]) diff --git a/src/dtddata.S b/src/dtddata.S new file mode 100644 index 00000000..53debf35 --- /dev/null +++ b/src/dtddata.S @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* from: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967#comment-348129 */ + +.altmacro +.macro binfile name file + .p2align 2 + .globl \name&_begin +\name&_begin: + .incbin \file +\name&_end: + .byte 0 + .p2align 2 + .globl \name&_len +\name&_len: + .int (\name&_end - \name&_begin) +.endm + +.section .rodata +binfile DTD_DATA "src/wayland.dtd.embed" diff --git a/src/scanner.c b/src/scanner.c index 8ecdd56e..406519f7 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -25,6 +25,8 @@ * SOFTWARE. */ +#include "config.h" + #include <stdbool.h> #include <stdio.h> #include <stdarg.h> @@ -34,9 +36,18 @@ #include <expat.h> #include <getopt.h> #include <limits.h> +#include <unistd.h> + +#if HAVE_LIBXML +#include <libxml/parser.h> +#endif #include "wayland-util.h" +/* Embedded wayland.dtd file, see dtddata.S */ +extern char DTD_DATA_begin; +extern int DTD_DATA_len; + enum side { CLIENT, SERVER, @@ -59,6 +70,57 @@ usage(int ret) exit(ret); } +static bool +is_dtd_valid(FILE *input) +{ + bool rc = true; +#if HAVE_LIBXML + xmlParserCtxtPtr ctx = NULL; + xmlDocPtr doc = NULL; + xmlDtdPtr dtd = NULL; + xmlValidCtxtPtr dtdctx; + xmlParserInputBufferPtr buffer; + int fd = fileno(input); + + dtdctx = xmlNewValidCtxt(); + ctx = xmlNewParserCtxt(); + if (!ctx || !dtdctx) + abort(); + + buffer = xmlParserInputBufferCreateMem(&DTD_DATA_begin, + DTD_DATA_len, + XML_CHAR_ENCODING_UTF8); + if (!buffer) { + fprintf(stderr, "Failed to init buffer for DTD.\n"); + abort(); + } + + dtd = xmlIOParseDTD(NULL, buffer, XML_CHAR_ENCODING_UTF8); + if (!dtd) { + fprintf(stderr, "Failed to parse DTD.\n"); + abort(); + } + + doc = xmlCtxtReadFd(ctx, fd, "protocol", NULL, 0); + if (!doc) { + fprintf(stderr, "Failed to read XML\n"); + abort(); + } + + rc = xmlValidateDtd(dtdctx, doc, dtd); + xmlFreeDoc(doc); + xmlFreeParserCtxt(ctx); + xmlFreeValidCtxt(dtdctx); + /* xmlIOParseDTD consumes buffer */ + + if (lseek(fd, 0, SEEK_SET) != 0) { + fprintf(stderr, "Failed to reset fd, output would be garbage.\n"); + abort(); + } +#endif + return rc; +} + #define XML_BUFFER_SIZE 4096 struct location { @@ -1617,6 +1679,15 @@ int main(int argc, char *argv[]) ctx.protocol = &protocol; ctx.loc.filename = "<stdin>"; + if (!is_dtd_valid(input)) { + fprintf(stderr, + "*******************************************************\n" + "* *\n" + "* WARNING: XML failed validation against built-in DTD *\n" + "* *\n" + "*******************************************************\n"); + } + /* create XML parser */ ctx.parser = XML_ParserCreate(NULL); XML_SetUserData(ctx.parser, &ctx); From 3dc7c2c84675483ca0a018ae8f66ebad5639a0bc Mon Sep 17 00:00:00 2001 From: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Date: Wed, 18 Nov 2015 12:54:10 +0200 Subject: [PATCH 0222/1152] Makefile: use automake rule for compiling .S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automake seems to have its own rules for compiling an .o from an .S. Essentially it does the same as our hand-crafted rule, but adds some things like dependency file generation. Remove our hand-crafted rule to use the automake rule, it is less surprising. http://www.gnu.org/software/automake/manual/html_node/Assembly-Support.html Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Víctor Jáquez <vjaquez@igalia.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> --- Makefile.am | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7d31a392..e850abce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,9 +30,6 @@ pkgconfig_DATA += src/wayland-scanner.pc src/dtddata.o: protocol/wayland.dtd -%.o: %.S - $(AM_V_GEN)$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c -o $@ $< - if USE_HOST_SCANNER wayland_scanner = wayland-scanner else From b644594a2ce918e6a9d3dde5d3d60a1405a0ffd9 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Date: Wed, 18 Nov 2015 13:00:00 +0200 Subject: [PATCH 0223/1152] scanner: drop altmacro from dtddata.S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using .altmacro in dtddata.S, because clang does not yet implement it. Turns out that we do not actually seem to need it, and we can modify the syntax to work without it. Moving the double quotes from the binfile line to the .incbin line is required to avoid the assembler error "missing string". Instead of & we now use \() to mark the end of macro argument name. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92988 Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Víctor Jáquez <vjaquez@igalia.com> Acked-by: Peter Hutterer <peter.hutterer@who-t.net> --- src/dtddata.S | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/dtddata.S b/src/dtddata.S index 53debf35..68e3435a 100644 --- a/src/dtddata.S +++ b/src/dtddata.S @@ -22,19 +22,18 @@ /* from: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967#comment-348129 */ -.altmacro .macro binfile name file .p2align 2 - .globl \name&_begin -\name&_begin: - .incbin \file -\name&_end: + .globl \name\()_begin +\name\()_begin: + .incbin "\file" +\name\()_end: .byte 0 .p2align 2 - .globl \name&_len -\name&_len: - .int (\name&_end - \name&_begin) + .globl \name\()_len +\name\()_len: + .int (\name\()_end - \name\()_begin) .endm .section .rodata -binfile DTD_DATA "src/wayland.dtd.embed" +binfile DTD_DATA src/wayland.dtd.embed From a5ef9304fe342cf012aba36cef066f61b03236d7 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Wed, 18 Nov 2015 09:44:11 -0600 Subject: [PATCH 0224/1152] protocol: Remove incorrect statement that attach must precede damage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation for wl_surface.commit makes it clear that the application of damage follows attach during the commit, so it doesn't matter what order the app sends the requests. Many existing apps post damage before attaching a buffer already, and it's really quite reasonable to do so. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- protocol/wayland.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 9c22d45e..525e0925 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1095,10 +1095,8 @@ <description summary="mark part of the surface damaged"> This request is used to describe the regions where the pending buffer is different from the current surface contents, and where - the surface therefore needs to be repainted. The pending buffer - must be set by wl_surface.attach before sending damage. The - compositor ignores the parts of the damage that fall outside of - the surface. + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. From d5f22d29dfb46b755b1d0565c20fbf092a06526b Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Mon, 23 Nov 2015 14:28:28 +1000 Subject: [PATCH 0225/1152] protocol: fix a couple of whitespace issues 8 spaces is one tab Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> --- protocol/wayland.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 525e0925..f9e6d763 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1347,7 +1347,7 @@ <event name="capabilities"> <description summary="seat capabilities changed"> - This is emitted whenever a seat gains or loses the pointer, + This is emitted whenever a seat gains or loses the pointer, keyboard or touch capabilities. The argument is a capability enum containing the complete set of capabilities this seat has. </description> @@ -1356,33 +1356,33 @@ <request name="get_pointer"> <description summary="return pointer object"> - The ID provided will be initialized to the wl_pointer interface + The ID provided will be initialized to the wl_pointer interface for this seat. - This request only takes effect if the seat has the pointer - capability. + This request only takes effect if the seat has the pointer + capability. </description> <arg name="id" type="new_id" interface="wl_pointer"/> </request> <request name="get_keyboard"> <description summary="return keyboard object"> - The ID provided will be initialized to the wl_keyboard interface + The ID provided will be initialized to the wl_keyboard interface for this seat. - This request only takes effect if the seat has the keyboard - capability. + This request only takes effect if the seat has the keyboard + capability. </description> <arg name="id" type="new_id" interface="wl_keyboard"/> </request> <request name="get_touch"> <description summary="return touch object"> - The ID provided will be initialized to the wl_touch interface + The ID provided will be initialized to the wl_touch interface for this seat. - This request only takes effect if the seat has the touch - capability. + This request only takes effect if the seat has the touch + capability. </description> <arg name="id" type="new_id" interface="wl_touch"/> </request> @@ -1568,7 +1568,7 @@ <request name="release" type="destructor" since="3"> <description summary="release the pointer object"> - Using this request client can tell the server that it is not going to + Using this request client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so user must not call From 389c84e24868d68141364093ad0acd372c6195f4 Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Fri, 27 Nov 2015 15:39:45 +0100 Subject: [PATCH 0226/1152] server: remove redundant include we don't use ffi in wayland-server.c Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/wayland-server.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 0f04f661..1364d5de 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -42,7 +42,6 @@ #include <fcntl.h> #include <sys/file.h> #include <sys/stat.h> -#include <ffi.h> #include "wayland-private.h" #include "wayland-server.h" From 3384f69ecf043d62a4e036c0353c2daa01d7c4d0 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Mon, 30 Nov 2015 10:55:04 -0600 Subject: [PATCH 0227/1152] protocol: Add wl_surface.damage_buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wl_surface.damage uses surface local co-ordinates. Buffer scale and buffer transforms came along, and EGL surfaces have no understanding of them. Theoretically, clients pass damage rectangles - in Y-inverted surface co-ordinates) to EGLSwapBuffersWithDamage, and the EGL implementation passed them on to wayland. However, for this to work the EGL implementation must be able to flip those rectangles into the space the compositor is expecting, but it's unable to do so because it doesn't know the height of the transformed buffer. So, currently, EGLSwapBuffersWithDamage is unusable and EGLSwapBuffers has to pass (0,0) - (INT32_MAX, INT32_MAX) damage to function. wl_surface.damage_buffer allows damage to be registered on a surface in buffer co-ordinates, avoiding this problem. Credit where it's due, these ideas are not entirely my own: Over a year ago the idea of changing damage co-ordinates to buffer co-ordinates was suggested (by Jason Ekstrand), and it was at least partially rejected and abandoned. At the time it was also suggested (by Pekka Paalanen) that adding a new wl_surface.damage_buffer request was another option. This will eventually resolve: https://bugs.freedesktop.org/show_bug.cgi?id=78190 by making the problem irrelevant. Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Jason Ekstrand <jason@jlekstrand.net> Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> --- protocol/wayland.xml | 50 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f9e6d763..7ca5049b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -176,7 +176,7 @@ </event> </interface> - <interface name="wl_compositor" version="3"> + <interface name="wl_compositor" version="4"> <description summary="the compositor singleton"> A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple @@ -986,7 +986,7 @@ </event> </interface> - <interface name="wl_surface" version="3"> + <interface name="wl_surface" version="4"> <description summary="an onscreen surface"> A surface is a rectangular area that is displayed on the screen. It has a location, size and pixel contents. @@ -1109,6 +1109,10 @@ wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. + + Alternatively, damage can be posted with wl_surface.damage_buffer + which uses buffer co-ordinates instead of surface co-ordinates, + and is probably the preferred and intuitive way of doing this. </description> <arg name="x" type="int"/> @@ -1325,6 +1329,48 @@ </description> <arg name="scale" type="int"/> </request> + + <!-- Version 4 additions --> + <request name="damage_buffer" since="4"> + <description summary="mark part of the surface damaged using buffer co-ordinates"> + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. + + Damage is double-buffered state, see wl_surface.commit. + + The damage rectangle is specified in buffer coordinates. + + The initial value for pending damage is empty: no damage. + wl_surface.damage_buffer adds pending damage: the new pending + damage is the union of old pending damage and the given rectangle. + + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. + + This request differs from wl_surface.damage in only one way - it + takes damage in buffer co-ordinates instead of surface local + co-ordinates. While this generally is more intuitive than surface + co-ordinates, it is especially desirable when using wp_viewport + or when a drawing library (like EGL) is unaware of buffer scale + and buffer transform. + + Note: Because buffer transformation changes and damage requests may + be interleaved in the protocol stream, It is impossible to determine + the actual mapping between surface and buffer damage until + wl_surface.commit time. Therefore, compositors wishing to take both + kinds of damage into account will have to accumulate damage from the + two requests separately and only transform from one to the other + after receiving the wl_surface.commit. + </description> + + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + </request> </interface> <interface name="wl_seat" version="5"> From 87321d0f2fb61a3808e7a0cc1d71f82d065b2cd2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Mon, 7 Dec 2015 15:43:35 +1000 Subject: [PATCH 0228/1152] protocol: specify behavior of get_pointer when capabilities change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also applies to touch/keyboard Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> --- protocol/wayland.xml | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 7ca5049b..df8ed19b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1396,6 +1396,27 @@ This is emitted whenever a seat gains or loses the pointer, keyboard or touch capabilities. The argument is a capability enum containing the complete set of capabilities this seat has. + + When the pointer capability is added, a client may create a + wl_pointer object using the wl_seat.get_pointer request. This object + will receive pointer events until the capability is removed in the + future. + + When the pointer capability is removed, a client should destroy the + wl_pointer objects associated with the seat where the capability was + removed, using the wl_pointer.release request. No further pointer + events will be received on these objects. + + In some compositors, if a seat regains the pointer capability and a + client has a previously obtained wl_pointer object of version 4 or + less, that object may start sending pointer events again. This + behavior is considered a misinterpretation of the intended behavior + and must not be relied upon by the client. wl_pointer objects of + version 5 or later must not send events if created before the most + recent event notifying the client of an added pointer capability. + + The above behavior also applies to wl_keyboard and wl_touch with the + keyboard and touch capabilities, respectively. </description> <arg name="capabilities" type="uint" enum="capability"/> </event> @@ -1406,7 +1427,9 @@ for this seat. This request only takes effect if the seat has the pointer - capability. + capability, or has had the pointer capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the pointer capability. </description> <arg name="id" type="new_id" interface="wl_pointer"/> </request> @@ -1417,7 +1440,9 @@ for this seat. This request only takes effect if the seat has the keyboard - capability. + capability, or has had the keyboard capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the keyboard capability. </description> <arg name="id" type="new_id" interface="wl_keyboard"/> </request> @@ -1428,7 +1453,9 @@ for this seat. This request only takes effect if the seat has the touch - capability. + capability, or has had the touch capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the touch capability. </description> <arg name="id" type="new_id" interface="wl_touch"/> </request> From 225830dcb8bf1a6583d0f4ca182584024783923e Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Thu, 17 Dec 2015 16:49:59 -0800 Subject: [PATCH 0229/1152] server: Add a socket with an existing fd This adds functionality to allow system-level control over handing out file descriptors for sockets, to allow tighter security when running a Wayland compositor under a Wayland session server. Allows writing socket activated Wayland servers. Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Cc: Sung-Jin Park <sj76.park@samsung.com> Cc: Sangjin Lee <lsj119@samsung.com> --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 85b4b9e6..1700cd34 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -131,6 +131,9 @@ wl_display_add_socket(struct wl_display *display, const char *name); const char * wl_display_add_socket_auto(struct wl_display *display); +int +wl_display_add_socket_fd(struct wl_display *display, int sock_fd); + void wl_display_terminate(struct wl_display *display); diff --git a/src/wayland-server.c b/src/wayland-server.c index 1364d5de..55c0cf92 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1198,6 +1198,49 @@ wl_display_add_socket_auto(struct wl_display *display) return NULL; } +/** Add a socket with an existing fd to Wayland display for the clients to connect. + * + * \param display Wayland display to which the socket should be added. + * \param sock_fd The existing socket file descriptor to be used + * \return 0 if success. -1 if failed. + * + * The existing socket fd must already be created, opened, and locked. + * The fd must be properly set to CLOEXEC and bound to a socket file + * with both bind() and listen() already called. + * + * \memberof wl_display + */ +WL_EXPORT int +wl_display_add_socket_fd(struct wl_display *display, int sock_fd) +{ + struct wl_socket *s; + struct stat buf; + + /* Require a valid fd or fail */ + if (sock_fd < 0 || fstat(sock_fd, &buf) < 0 || !S_ISSOCK(buf.st_mode)) { + return -1; + } + + s = wl_socket_alloc(); + if (s == NULL) + return -1; + + /* Reuse the existing fd */ + s->fd = sock_fd; + + s->source = wl_event_loop_add_fd(display->loop, s->fd, + WL_EVENT_READABLE, + socket_data, display); + if (s->source == NULL) { + wl_log("failed to establish event source\n"); + return -1; + } + + wl_list_insert(display->socket_list.prev, &s->link); + + return 0; +} + /** Add a socket to Wayland display for the clients to connect. * * \param display Wayland display to which the socket should be added. From 2f666ee34fb414f43def75c1caa1243feb349f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Wed, 4 Nov 2015 12:40:54 +0800 Subject: [PATCH 0230/1152] scanner: Add missing brackets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A statement was added at the same indentation level as the true branch of the if statement, but since there were no brackets, it would be executed independently of the result of the if condition. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/scanner.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 406519f7..3f79a443 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -612,10 +612,11 @@ start_element(void *data, const char *element_name, const char **atts) for (i = 0; atts[i]; i += 2) { if (strcmp(atts[i], "name") == 0) name = atts[i + 1]; - if (strcmp(atts[i], "version") == 0) + if (strcmp(atts[i], "version") == 0) { version = strtouint(atts[i + 1]); if (version == -1) fail(&ctx->loc, "wrong version (%s)", atts[i + 1]); + } if (strcmp(atts[i], "type") == 0) type = atts[i + 1]; if (strcmp(atts[i], "value") == 0) From 3de1783e5038639128bb37f2937eeee3e36aefe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Wed, 4 Nov 2015 14:21:52 +0800 Subject: [PATCH 0231/1152] scanner: Fail if 'since' is higher than the interface version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an event or request have a "since" attribute that is larger than the version of the interface it is in, fail with an explaining error message. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/scanner.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 3f79a443..b00f036a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -674,8 +674,12 @@ start_element(void *data, const char *element_name, const char **atts) if (since != NULL) { version = strtouint(since); - if (version == -1) + if (version == -1) { fail(&ctx->loc, "invalid integer (%s)\n", since); + } else if (version > ctx->interface->version) { + fail(&ctx->loc, "since (%u) larger than version (%u)\n", + version, ctx->interface->version); + } } else { version = 1; } From 2e7fb786825472d2a4b717e0b82d216aa90fb3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Wed, 26 Aug 2015 12:00:06 +0800 Subject: [PATCH 0232/1152] Use zalloc instead of malloc + memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/connection.c | 4 ++-- src/wayland-client.c | 12 +++--------- src/wayland-private.h | 7 +++++++ src/wayland-server.c | 6 ++---- src/wayland-shm.c | 4 +--- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/connection.c b/src/connection.c index 6742f19c..45a2e784 100644 --- a/src/connection.c +++ b/src/connection.c @@ -163,10 +163,10 @@ wl_connection_create(int fd) { struct wl_connection *connection; - connection = malloc(sizeof *connection); + connection = zalloc(sizeof *connection); if (connection == NULL) return NULL; - memset(connection, 0, sizeof *connection); + connection->fd = fd; return connection; diff --git a/src/wayland-client.c b/src/wayland-client.c index 509be08c..613767ee 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -331,12 +331,10 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface) struct wl_proxy *proxy; struct wl_display *display = factory->display; - proxy = malloc(sizeof *proxy); + proxy = zalloc(sizeof *proxy); if (proxy == NULL) return NULL; - memset(proxy, 0, sizeof *proxy); - proxy->object.interface = interface; proxy->display = display; proxy->queue = factory->queue; @@ -387,12 +385,10 @@ wl_proxy_create_for_id(struct wl_proxy *factory, struct wl_proxy *proxy; struct wl_display *display = factory->display; - proxy = malloc(sizeof *proxy); + proxy = zalloc(sizeof *proxy); if (proxy == NULL) return NULL; - memset(proxy, 0, sizeof *proxy); - proxy->object.interface = interface; proxy->object.id = id; proxy->display = display; @@ -817,14 +813,12 @@ wl_display_connect_to_fd(int fd) if (debug && (strstr(debug, "client") || strstr(debug, "1"))) debug_client = 1; - display = malloc(sizeof *display); + display = zalloc(sizeof *display); if (display == NULL) { close(fd); return NULL; } - memset(display, 0, sizeof *display); - display->fd = fd; wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE); wl_event_queue_init(&display->default_queue, display); diff --git a/src/wayland-private.h b/src/wayland-private.h index 58ac952b..0e3420c3 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -29,6 +29,7 @@ #define WAYLAND_PRIVATE_H #include <stdarg.h> +#include <stdlib.h> #define WL_HIDE_DEPRECATED 1 @@ -216,4 +217,10 @@ struct wl_display; struct wl_array * wl_display_get_additional_shm_formats(struct wl_display *display); +static inline void * +zalloc(size_t s) +{ + return calloc(1, s); +} + #endif diff --git a/src/wayland-server.c b/src/wayland-server.c index 55c0cf92..9e26b185 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -415,11 +415,10 @@ wl_client_create(struct wl_display *display, int fd) struct wl_client *client; socklen_t len; - client = malloc(sizeof *client); + client = zalloc(sizeof *client); if (client == NULL) return NULL; - memset(client, 0, sizeof *client); client->display = display; client->source = wl_event_loop_add_fd(display->loop, fd, WL_EVENT_READABLE, @@ -854,11 +853,10 @@ wl_socket_alloc(void) { struct wl_socket *s; - s = malloc(sizeof *s); + s = zalloc(sizeof *s); if (!s) return NULL; - memset(s, 0, sizeof *s); s->fd = -1; s->fd_lock = -1; diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 0cd8c118..359c3bd5 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -536,12 +536,10 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer) sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); if (sigbus_data == NULL) { - sigbus_data = malloc(sizeof *sigbus_data); + sigbus_data = zalloc(sizeof *sigbus_data); if (sigbus_data == NULL) return; - memset(sigbus_data, 0, sizeof *sigbus_data); - pthread_setspecific(wl_shm_sigbus_data_key, sigbus_data); } From edbee66cbd11f2b186831ac6c92937f638586961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Tue, 29 Dec 2015 09:46:11 +0800 Subject: [PATCH 0233/1152] doc: Fix function membership MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put the various misplaced functions in the right class; partly because its where they belong, and partly to make intra-class \ref(erences) happy. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/wayland-client-core.h | 4 ++-- src/wayland-client.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 8b4b4b84..a7293952 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -103,8 +103,8 @@ struct wl_proxy; * queue, reading all the data from the display fd. If the application * would call \em poll(2) after that it would block, even though there * might be events queued on the default queue. Those events should be - * dispatched with \ref wl_display_dispatch_(queue_)pending() before - * flushing and blocking. + * dispatched with \ref wl_display_dispatch_pending() or \ref + * wl_display_dispatch_queue_pending() before flushing and blocking. */ struct wl_display; diff --git a/src/wayland-client.c b/src/wayland-client.c index 613767ee..27960309 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -309,7 +309,7 @@ wl_event_queue_destroy(struct wl_event_queue *queue) * \return A new event queue associated with this display or NULL on * failure. * - * \memberof wl_event_queue + * \memberof wl_display */ WL_EXPORT struct wl_event_queue * wl_display_create_queue(struct wl_display *display) @@ -965,7 +965,7 @@ static const struct wl_callback_listener sync_listener = { * with calling wl_display_prepare_read() and wl_display_read_events()) * * \sa wl_display_roundtrip() - * \memberof wl_event_queue + * \memberof wl_display */ WL_EXPORT int wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue) @@ -1465,7 +1465,7 @@ wl_display_prepare_read_queue(struct wl_display *display, * with the default queue passed as the queue. * * \sa wl_display_prepare_read_queue - * \memberof wl_event_queue + * \memberof wl_display */ WL_EXPORT int wl_display_prepare_read(struct wl_display *display) @@ -1527,7 +1527,7 @@ wl_display_cancel_read(struct wl_display *display) * \sa wl_display_dispatch(), wl_display_dispatch_pending(), * wl_display_dispatch_queue_pending() * - * \memberof wl_event_queue + * \memberof wl_display */ WL_EXPORT int wl_display_dispatch_queue(struct wl_display *display, @@ -1599,7 +1599,7 @@ wl_display_dispatch_queue(struct wl_display *display, * event queue. On failure -1 is returned and errno set appropriately. * If there are no events queued, this function returns immediately. * - * \memberof wl_event_queue + * \memberof wl_display * \since 1.0.2 */ WL_EXPORT int From ee9b69cfe0c94a297e1dea7cc4ff147d740c4294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Tue, 29 Dec 2015 09:47:20 +0800 Subject: [PATCH 0234/1152] doc: Fix incorrect parameter name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 359c3bd5..8e7adc92 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -404,7 +404,7 @@ wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) /** Unreference a shm_pool * - * \param buffer The pool object + * \param pool The pool object * * Drops a reference to a wl_shm_pool object. * From 0a37511ecc0117339e5e5d0add84a2f3b51493d2 Mon Sep 17 00:00:00 2001 From: Jaeyoon Jung <jaeyoon.jung@lge.com> Date: Tue, 12 Jan 2016 13:12:34 +0900 Subject: [PATCH 0235/1152] server: Calculate remaining data size after a closure is processed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When processing a closure, data in the connection can be consumed again if the closure itself invokes extra event dispatch. In that case the remaining data size is also altered, so the variable len should be updated after the closure is processed. Signed-off-by: Jaeyoon Jung <jaeyoon.jung@lge.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/connection.c | 8 +++++++- src/wayland-private.h | 3 +++ src/wayland-server.c | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index 45a2e784..bc373f6b 100644 --- a/src/connection.c +++ b/src/connection.c @@ -314,6 +314,12 @@ wl_connection_flush(struct wl_connection *connection) return connection->out.head - tail; } +uint32_t +wl_connection_pending_input(struct wl_connection *connection) +{ + return wl_buffer_size(&connection->in); +} + int wl_connection_read(struct wl_connection *connection) { @@ -350,7 +356,7 @@ wl_connection_read(struct wl_connection *connection) connection->in.head += len; - return connection->in.head - connection->in.tail; + return wl_connection_pending_input(connection); } int diff --git a/src/wayland-private.h b/src/wayland-private.h index 0e3420c3..da578d16 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -122,6 +122,9 @@ wl_connection_consume(struct wl_connection *connection, size_t size); int wl_connection_flush(struct wl_connection *connection); +uint32_t +wl_connection_pending_input(struct wl_connection *connection); + int wl_connection_read(struct wl_connection *connection); diff --git a/src/wayland-server.c b/src/wayland-server.c index 9e26b185..2158c088 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -313,7 +313,6 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) closure = wl_connection_demarshal(client->connection, size, &client->objects, message); - len -= size; if (closure == NULL && errno == ENOMEM) { wl_resource_post_no_memory(resource); @@ -346,6 +345,8 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) if (client->error) break; + + len = wl_connection_pending_input(connection); } if (client->error) From 693bf00083c372de4da785810429498d215d0c85 Mon Sep 17 00:00:00 2001 From: Victor Berger <victor.berger@m4x.org> Date: Mon, 4 Jan 2016 11:09:01 +0100 Subject: [PATCH 0236/1152] client: Add missing arg in a wl_log invocation Without this 'proxy' argument, the '%p' formatter prints a constant garbage value. Signed-off-by: Victor Berger <victor.berger@m4x.org> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 27960309..15eba6e4 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -511,7 +511,7 @@ wl_proxy_add_dispatcher(struct wl_proxy *proxy, const void *implementation, void *data) { if (proxy->object.implementation || proxy->dispatcher) { - wl_log("proxy %p already has listener\n"); + wl_log("proxy %p already has listener\n", proxy); return -1; } From 1b7191743eeeecedd66af03eeb960c5978fc8335 Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Mon, 11 Jan 2016 11:45:12 +0100 Subject: [PATCH 0237/1152] server: don't send an error to NULL display_resource if display_resource = wl_resource_create() fails in bind_display(), we call wl_client_post_no_memory() which is wrong, since this function uses display_resource (which is NULL at this point). said simply: don't send an error to resource that you've just failed to create) https://bugs.freedesktop.org/show_bug.cgi?id=91356 Reported-by: Ashim <ashim.shah@samsung.com> Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 2158c088..2cfbb4a3 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -779,7 +779,8 @@ bind_display(struct wl_client *client, struct wl_display *display) client->display_resource = wl_resource_create(client, &wl_display_interface, 1, 1); if (client->display_resource == NULL) { - wl_client_post_no_memory(client); + /* DON'T send no-memory error to client - it has no + * resource to which it could post the event */ return -1; } From 69a5a6d16c3ce97d6032ad61ba3503c8e598d359 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Mon, 7 Dec 2015 22:49:13 -0800 Subject: [PATCH 0238/1152] socket-test: Fix some comment typos Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> --- tests/socket-test.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/socket-test.c b/tests/socket-test.c index c53f972e..2e336fdc 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -107,11 +107,11 @@ TEST(add_existing_socket) ret = wl_display_add_socket(d, name); assert(ret == 0); - /* this on should fail */ + /* this one should fail */ ret = wl_display_add_socket(d, name); assert(ret < 0); - /* the original socket should still exists, + /* the original socket should still exist. * this was a bug introduced in e2c0d47b0c77f18cd90e9c6eabb358c4d89681c8 */ len = snprintf(path, sizeof example_sockaddr_un.sun_path, "%s/%s", xdg_runtime_dir, name); @@ -120,7 +120,7 @@ TEST(add_existing_socket) assert(access(path, F_OK) != -1); - /* still should exists the original socket */ + /* the original socket should still exist */ ret = wl_display_add_socket(d, name); assert(ret < 0); @@ -129,7 +129,9 @@ TEST(add_existing_socket) TEST(add_socket_auto) { - /* the number of auto sockets is currently 32 */ + /* the number of auto sockets is currently 32, + * set in wayland-server.c. + */ const int MAX_SOCKETS = 32; char path[sizeof example_sockaddr_un.sun_path]; @@ -153,7 +155,7 @@ TEST(add_socket_auto) assert(len < sizeof example_sockaddr_un.sun_path && "Bug in test. Path too long"); - /* was the socket? */ + /* was the socket created correctly? */ assert(access(path, F_OK) != -1); /* is the name sequential? */ From 2b236af9b7f21b81df9ded062921da6cc3f37eb9 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Mon, 7 Dec 2015 22:49:14 -0800 Subject: [PATCH 0239/1152] socket-test: Refactor if check into the assert Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> --- tests/socket-test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/socket-test.c b/tests/socket-test.c index 2e336fdc..bb034f43 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -47,8 +47,7 @@ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); - if (!val) - assert(0 && "set $XDG_RUNTIME_DIR to run this test"); + assert(val && "set $XDG_RUNTIME_DIR to run this test"); return val; } From c5356e9016aa814a873a765bb2cbe57e804e5ea7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Tue, 8 Dec 2015 11:11:07 +1000 Subject: [PATCH 0240/1152] protocol: add wl_pointer.frame, axis_source, axis_stop, and axis_discrete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The frame event groups separate pointer events together. The primary use-case for this at the moment is diagonal scrolling - a vertical/horizontal scroll event can be grouped together to calculate the correct motion vector. Frame events group all wl_pointer events. An example sequence of motion events followed by a diagonal scroll followed by a button event is: wl_pointer.motion wl_pointer.frame wl_pointer.motion wl_pointer.frame wl_pointer.axis wl_pointer.axis wl_pointer.frame wl_pointer.button wl_pointer.frame In the future, other extensions may insert additional information about an event into the frame. For example, an extension may add information about the physical device that generated an event into the frame. For this reason, enter/leave events are grouped by a frame event too. The axis_source event determines how an axis event was generated. That enables clients to judge when to use kinetic scrolling. Only one axis_source event is allowed per frame and applies to all events in this frame. The axis_stop event notifies a client about the termination of a scroll sequence, likewise needed to calculate kinetic scrolling parameters. Multiple axis_stop events within the same frame indicate that scrolling has stopped in all these axis at the same time. The axis_discrete event provides the wheel click count. Previously the axis value was some hardcoded number (10), with the discrete steps this enables a client to differ between line-based scrolling on a mouse wheel and smooth scrolling with a touchpad. The axis_discrete event carries the axis information and the discrete value and can occur at any time in the frame provided it is ordered before the matching axis event. Specifically, this sequence is valid: wl_pointer.axis_source wl_pointer.axis_discrete (vert) wl_pointer.axis_discrete (horiz) wl_pointer.axis (horiz) wl_pointer.axis (vert) wl_pointer.frame Enter and leave event also trigger wl_pointer.frame events, where possible the compositor should group leave and subsequent enter into the same frame. This indicates to the client that the pointer has moved between surfaces and may allow a client to shortcut code otherwise triggerd by the leave or enter events. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Carlos Garnacho <carlosg@gnome.org> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 150 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index df8ed19b..8a621904 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1482,7 +1482,7 @@ </interface> - <interface name="wl_pointer" version="3"> + <interface name="wl_pointer" version="5"> <description summary="pointer input device"> The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -1649,9 +1649,153 @@ </description> </request> + <!-- Version 5 additions --> + + <event name="frame" since="5"> + <description summary="end of a pointer event sequence"> + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. + + All wl_pointer events before a wl_pointer.frame event belong + logically together. For example, in a diagonal scroll motion the + compositor will send an optional wl_pointer.axis_source event, two + wl_pointer.axis events (horizontal and vertical) and finally a + wl_pointer.frame event. The client may use this information to + calculate a diagonal vector for scrolling. + + When multiple wl_pointer.axis events occur within the same frame, + the motion vector is the combined motion of all events. + When a wl_pointer.axis and a wl_pointer.axis_stop event occur within + the same frame, this indicates that axis movement in one axis has + stopped but continues in the other axis. + When multiple wl_pointer.axis_stop events occur within in the same + frame, this indicates that these axes stopped in the same instance. + + A wl_pointer.frame event is sent for every logical event group, + even if the group only contains a single wl_pointer event. + Specifically, a client may get a sequence: motion, frame, button, + frame, axis, frame, axis_stop, frame. + + The wl_pointer.enter and wl_pointer.leave events are logical events + generated by the compositor and not the hardware. These events are + also grouped by a wl_pointer.frame. When a pointer moves from one + surface to the another, a compositor should group the + wl_pointer.leave event within the same wl_pointer.frame. + However, a client must not rely on wl_pointer.leave and + wl_pointer.enter being in the same wl_pointer.frame. + Compositor-specific policies may require the wl_pointer.leave and + wl_pointer.enter event being split across multiple wl_pointer.frame + groups. + </description> + </event> + + <enum name="axis_source"> + <description summary="axis source types"> + Describes the source types for axis events. This indicates to the + client how an axis event was physically generated; a client may + adjust the user interface accordingly. For example, scroll events + from a "finger" source may be in a smooth coordinate space with + kinetic scrolling whereas a "wheel" source may be in discrete steps + of a number of lines. + + The "continuous" axis source is a device generating events in a + continuous coordinate space, but using something other than a + finger. One example for this source is button-based scrolling where + the vertical motion of a device is converted to scroll events while + a button is held down. + </description> + <entry name="wheel" value="0" summary="A physical wheel" /> + <entry name="finger" value="1" summary="Finger on a touch surface" /> + <entry name="continuous" value="2" summary="Continuous coordinate space"/> + </enum> + + <event name="axis_source" since="5"> + <description summary="axis source event"> + Source information for scroll and other axes. + + This event does not occur on its own. It is sent before a + wl_pointer.frame event and carries the source information for + all events within that frame. + + The source specifies how this event was generated. If the source is + wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be + sent when the user lifts the finger off the device. + + If the source is wl_pointer axis_source.wheel or + wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may + or may not be sent. Whether a compositor sends a axis_stop event + for these sources is hardware-specific and implementation-dependent; + clients must not rely on receiving an axis_stop event for these + scroll sources and should treat scroll sequences from these scroll + sources as unterminated by default. + + This event is optional. If the source is unknown for a particular + axis event sequence, no event is sent. + Only one wl_pointer.axis_source event is permitted per frame. + + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. + </description> + <arg name="axis_source" type="uint" enum="axis_source"/> + </event> + + <event name="axis_stop" since="5"> + <description summary="axis stop event"> + Stop notification for scroll and other axes. + + For some wl_pointer.axis_source types, a wl_pointer.axis_stop event + is sent to notify a client that the axis sequence has terminated. + This enables the client to implement kinetic scrolling. + See the wl_pointer.axis_source documentation for information on when + this event may be generated. + + Any wl_pointer.axis events with the same axis_source after this + event should be considered as the start of a new axis motion. + + The timestamp is to be interpreted identical to the timestamp in the + wl_pointer.axis event. The timestamp value may be the same as a + preceeding wl_pointer.axis event. + </description> + <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> + <arg name="axis" type="uint" enum="axis" summary="the axis stopped with this event"/> + </event> + + <event name="axis_discrete" since="5"> + <description summary="axis click event"> + Discrete step information for scroll and other axes. + + This event carries the axis value of the wl_pointer.axis event in + discrete steps (e.g. mouse wheel clicks). + + This event does not occur on its own, it is coupled with a + wl_pointer.axis event that represents this axis value on a + continuous scale. The protocol guarantees that each axis_discrete + event is always followed by exactly one axis event with the same + axis number within the same wl_pointer.frame. Note that the protocol + allows for other events to occur between the axis_discrete and + its coupled axis event, including other axis_discrete or axis + events. + + This event is optional; continuous scrolling devices + like two-finger scrolling on touchpads do not have discrete + steps and do not generate this event. + + The discrete value carries the directional information. e.g. a value + of -2 is two steps towards the negative direction of this axis. + + The axis number is identical to the axis number in the associate + axis event. + + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. + </description> + <arg name="axis" type="uint" enum="axis" /> + <arg name="discrete" type="int"/> + </event> </interface> - <interface name="wl_keyboard" version="4"> + <interface name="wl_keyboard" version="5"> <description summary="keyboard input device"> The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -1765,7 +1909,7 @@ </event> </interface> - <interface name="wl_touch" version="3"> + <interface name="wl_touch" version="5"> <description summary="touchscreen input device"> The wl_touch interface represents a touchscreen associated with a seat. From 16b4cc6902e2755522ce792ee2796df487c0860a Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 14 Jan 2016 11:02:17 -0600 Subject: [PATCH 0241/1152] server: improve failure log message for wl_global_create() The gratuitous %m jammed onto the end of the string prints errno concatenated with the word "version". I've removed the %m, and printed some additional information about the failure. Also, reversed the order of the expressions in the conditional to make it match the english in the log message. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-server.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 2cfbb4a3..c129b7d7 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -908,9 +908,10 @@ wl_global_create(struct wl_display *display, struct wl_global *global; struct wl_resource *resource; - if (interface->version < version) { - wl_log("wl_global_create: implemented version higher " - "than interface version%m\n"); + if (version > interface->version) { + wl_log("wl_global_create: implemented version for '%s' " + "higher than interface version (%d > %d)\n", + interface->name, version, interface->version); return NULL; } From 2b4c053924150d6652c42aa28ce70d173757ab0b Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 14 Jan 2016 11:02:18 -0600 Subject: [PATCH 0242/1152] server: Test for illegally low interface versions in wl_global_create() Any version lower than 1 is unreasonable. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-server.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index c129b7d7..3a7d79dd 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -908,6 +908,13 @@ wl_global_create(struct wl_display *display, struct wl_global *global; struct wl_resource *resource; + if (version < 1) { + wl_log("wl_global_create: failing to create interface " + "'%s' with version %d because it is less than 1\n", + interface->name, version); + return NULL; + } + if (version > interface->version) { wl_log("wl_global_create: implemented version for '%s' " "higher than interface version (%d > %d)\n", From 5c4272b8e9b16d632e89f1e9448abc370b957443 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho <carlosg@gnome.org> Date: Fri, 15 Jan 2016 21:11:39 +0100 Subject: [PATCH 0243/1152] protocol: Improve data source notification around DnD progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, there's no means for the DnD origin to know whether the destination is actually finished with the DnD transaction, short of finalizing it after the first transfer finishes, or leaking it forever. But this poses other interoperation problems, drag destinations might be requesting several mimetypes at once, might be just poking to find out the most suitable format, might want to defer the action to a popup, might be poking contents early before the selection was dropped... In addition, data_source.cancelled is suitable for the situations where the DnD operation fails (not on a drop target, no matching mimetypes, etc..), but seems undocumented for that use (and unused in weston's DnD). In order to improve the situation, the drag source should be notified of all stages of DnD. In addition to documenting the "cancelled" event for DnD purposes, The following 2 events have been added: - wl_data_source.dnd_drop_performed: Happens when the operation has been physically finished (eg. the button is released), it could be the right place to reset the pointer cursor back and undo any other state resulting from the initial button press. - wl_data_source.dnd_finished: Happens when the destination side destroys the wl_data_offer, at this point the source can just forget all data related to the DnD selection as well, plus optionally deleting the data on move operations. Changes since v6: - Turned wl_data_offer.finish calls with 0/NULL state/mimetype an error, made it explicit that it will only result in wl_data_offer.dnd_finished being sent if successful. Changes since v5: - Further rewording of wl_data_offer.finish and wl_data_offer.accept. Added error for untimely wl_data_offer.finish requests. Changes since v4: - Applied rewording suggestions from Jonas Ådahl. Added new wl_data_offer.finish request to allow explicit finalization on the destination side. Changes since v3: - Renamed dnd_performed to a more descriptive dnd_drop_performed, documented backwards compatible behavior on wl_data_offer.accept and wl_data_source.cancelled. Changes since v2: - Minor rewording. Changes since v1: - Renamed events to have a common "dnd" namespace. Made dnd_performed to happen invariably, data_device.cancelled may still happen afterwards. Signed-off-by: Carlos Garnacho <carlosg@gnome.org> Reviewed-by: Michael Catanzaro <mcatanzaro@igalia.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Mike Blumenkrantz <zmike@samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 87 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8a621904..7330b6f6 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -408,7 +408,7 @@ </interface> - <interface name="wl_data_offer" version="1"> + <interface name="wl_data_offer" version="3"> <description summary="offer to transfer data"> A wl_data_offer represents a piece of data offered for transfer by another client (the source client). It is used by the @@ -418,12 +418,27 @@ data directly from the source client. </description> + <enum name="error"> + <entry name="invalid_finish" value="0" + summary="finish request was called untimely"/> + </enum> + <request name="accept"> <description summary="accept one of the offered mime types"> Indicate that the client can accept the given mime type, or NULL for not accepted. - Used for feedback during drag-and-drop. + For objects of version 2 or older, this request is used by the + client to give feedback whether the client can receive the given + mime type, or NULL if none is accepted; the feedback does not + determine whether the drag-and-drop operation succeeds or not. + + For objects of version 3 or newer, this request determines the + final result of the drag-and-drop operation. If the end result + is that no mime types were accepted, the drag-and-drop operation + will be cancelled and the corresponding drag source will receive + wl_data_source.cancelled. Clients may still use this event in + conjunction with wl_data_source.action for feedback. </description> <arg name="serial" type="uint"/> @@ -442,6 +457,11 @@ The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. + + This request may happen multiple times for different mimetypes, + both before and after wl_data_device.drop. Drag-and-drop destination + clients may preemptively fetch data or examine it more closely to + determine acceptance. </description> <arg name="mime_type" type="string"/> <arg name="fd" type="fd"/> @@ -461,9 +481,26 @@ <arg name="mime_type" type="string"/> </event> + + <!-- Version 3 additions --> + + <request name="finish" since="3"> + <description summary="the offer will no longer be used"> + Notifies the compositor that the drag destination successfully + finished the drag-and-drop operation. + + Upon receiving this request, the compositor will emit + wl_data_source.dnd_finished on the drag source client. + + It is a client error to perform other requests than + wl_data_offer.destroy after this one. It is also an error to perform + this request after a NULL mime type has been set in + wl_data_offer.accept. + </description> + </request> </interface> - <interface name="wl_data_source" version="1"> + <interface name="wl_data_source" version="3"> <description summary="offer to transfer data"> The wl_data_source object is the source side of a wl_data_offer. It is created by the source client in a data transfer and @@ -510,14 +547,52 @@ <event name="cancelled"> <description summary="selection was cancelled"> - This data source has been replaced by another data source. + This data source is no longer valid. There are several reasons why + this could happen: + + - The data source has been replaced by another data source. + - The drag-and-drop operation was performed, but the drop destination + did not accept any of the mimetypes offered through + wl_data_source.target. + - The drag-and-drop operation was performed but didn't happen over a + surface. + - The compositor cancelled the drag-and-drop operation (e.g. compositor + dependent timeouts to avoid stale drag-and-drop transfers). + The client should clean up and destroy this data source. + + For objects of version 2 or older, wl_data_source.cancelled will + only be emitted if the data source was replaced by another data + source. </description> </event> + <!-- Version 3 additions --> + + <event name="dnd_drop_performed" since="3"> + <description summary="the drag-and-drop operation physically finished"> + The user performed the drop action. This event does not indicate + acceptance, wl_data_source.cancelled may still be emitted afterwards + if the drop destination does not accept any mimetype. + + However, this event might however not be received if the compositor + cancelled the drag-and-drop operation before this event could happen. + + Note that the data_source may still be used in the future and should + not be destroyed here. + </description> + </event> + + <event name="dnd_finished" since="3"> + <description summary="the drag-and-drop operation concluded"> + The drop destination finished interoperating with this data + source, so the client is now free to destroy this data source and + free all associated data. + </description> + </event> </interface> - <interface name="wl_data_device" version="2"> + <interface name="wl_data_device" version="3"> <description summary="data transfer device"> There is one wl_data_device per seat which can be obtained from the global wl_data_device_manager singleton. @@ -659,7 +734,7 @@ </request> </interface> - <interface name="wl_data_device_manager" version="2"> + <interface name="wl_data_device_manager" version="3"> <description summary="data transfer interface"> The wl_data_device_manager is a singleton global object that provides access to inter-client data transfer mechanisms such as From da7b2489041ef465158601087ed0ef6d2e68445d Mon Sep 17 00:00:00 2001 From: Carlos Garnacho <carlosg@gnome.org> Date: Fri, 15 Jan 2016 21:11:40 +0100 Subject: [PATCH 0244/1152] protocol: Add DnD actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These 2 requests have been added: - wl_data_source.set_actions: Notifies the compositor of the available actions on the data source. - wl_data_offer.set_actions: Notifies the compositor of the available actions on the destination side, plus the preferred action. Out of the data from these requests, the compositor can determine the action both parts agree on (and let the user play a role through eg. keyboard modifiers). The chosen option will be notified to both parties through the following two requests: - wl_data_source.action - wl_data_offer.action In addition, the destination side can peek the source side actions through wl_data_offer.source_actions. Compared to the XDND protocol, there's two notable changes: - XDND lets the source suggest an action, whereas wl_data_device lets the destination prefer a given action. The difference is subtle here, it comes off as convenience because it is the drag destination which receives the motion events (unlike in X) and can perform action updates. The drag destination seems also in a better position to update the preferred action based on things like the data being transferred, the place being dropped, and whether the drag is client-local. - That same source-side preferred action is used in XDND to convey the modifier-induced action to the drag destination, which would then ack it, or reply with another action that's accepted (or none), this makes the XdndPosition/XdndStatus messaging very verbose, and synchronous because the drag source always needs to know the latest status/action for every position+action sent. Here it's the compositor which takes care of modifiers and matching available/accepted actions, this allows for the signaling to happen only whenever the actions/modifiers change for real. Roughly based on previous work by Giulio Camuffo <giuliocamuffo@gmail.com> Changes since v10: - Narrow down the situations where wl_data_source/offer.accept requests are supposed to happen. Changes since v9: - Deferred the protocol errors to .finish after some IRC chat with Jonas, added further errors if actions API is used on selection sources/offers. Changes since v8: - Defined further the expected behavior on "ask", described the protocol errors that may happen. Fix more spaces vs tabs issues. Changes since v7: - Misc changes after updating the progress notification patch. Changes since v6: - Further explanations on wl_data_source/offer.set_actions, including a description of "ask" actions. Added protocol errors for unknown action values. Changes since v5: - Applied rewording suggestions from Jonas Ådahl. Dropped slot reservation scheme for actions. Fixed indentation and other minor formatting issues. Changes since v4: - Minor rewording. Changes since v3: - Splitted from DnD progress notification changes. - Further rationales in commit log. Changes since v2: - Renamed notify_actions to set_actions on both sides, seems more consistent with the rest of the protocol. - Spelled out better which events may be triggered on the compositor side by the requests, the circumstances in which events are emitted, and what are events useful for in clients. - Defined a minimal common ground wrt compositor-side action picking and keybindings. - Acknowledge the possibility of compositor/toolkit defined actions, even though none are used at the moment. Changes since v1: - Added wl_data_offer.source_actions to let know of the actions offered by a data source. - Renamed wl_data_source.finished to "drag_finished" for clarity - Improved wording as suggested by Bryce Signed-off-by: Carlos Garnacho <carlosg@gnome.org> Reviewed-by: Michael Catanzaro <mcatanzaro@igalia.com> Reviewed-by: Mike Blumenkrantz <zmike@samsung.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 205 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 7330b6f6..b223bb4a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -421,6 +421,12 @@ <enum name="error"> <entry name="invalid_finish" value="0" summary="finish request was called untimely"/> + <entry name="invalid_action_mask" value="1" + summary="action mask contains invalid values"/> + <entry name="invalid_action" value="2" + summary="action argument has an invalid value"/> + <entry name="invalid_offer" value="3" + summary="offer doesn't accept this request"/> </enum> <request name="accept"> @@ -495,9 +501,98 @@ It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in - wl_data_offer.accept. + wl_data_offer.accept or no action was received through + wl_data_offer.action. </description> </request> + + <request name="set_actions" since="3"> + <description summary="set the available/preferred drag-and-drop actions"> + Sets the actions that the destination side client supports for + this operation. This request may trigger the emission of + wl_data_source.action and wl_data_offer.action events if the compositor + need to change the selected action. + + This request can be called multiple times throughout the + drag-and-drop operation, typically in response to wl_data_device.enter + or wl_data_device.motion events. + + This request determines the final result of the drag-and-drop + operation. If the end result is that no action is accepted, + the drag source will receive wl_drag_source.cancelled. + + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, and the preferred_action + argument must only contain one of those values set, otherwise it + will result in a protocol error. + + While managing an "ask" action, the destination drag-and-drop client + may perform further wl_data_offer.receive requests, and is expected + to perform one last wl_data_offer.set_actions request with a preferred + action other than "ask" (and optionally wl_data_offer.accept) before + requesting wl_data_offer.finish, in order to convey the action selected + by the user. If the preferred action is not in the + wl_data_offer.source_actions mask, an error will be raised. + + If the "ask" action is dismissed (e.g. user cancellation), the client + is expected to perform wl_data_offer.destroy right away. + + This request can only be made on drag-and-drop offers, a protocol error + will be raised otherwise. + </description> + <arg name="dnd_actions" type="uint"/> + <arg name="preferred_action" type="uint"/> + </request> + + <event name="source_actions" since="3"> + <description summary="notify the source-side available actions"> + This event indicates the actions offered by the data source. It + will be sent right after wl_data_device.enter, or anytime the source + side changes its offered actions through wl_data_source.set_actions. + </description> + <arg name="source_actions" type="uint"/> + </event> + + <event name="action" since="3"> + <description summary="notify the selected action"> + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. + + This event can be emitted multiple times during the drag-and-drop + operation in response to destination side action changes through + wl_data_offer.set_actions. + + This event will no longer be emitted after wl_data_device.drop + happened on the drag-and-drop destination, the client must + honor the last action received, or the last preferred one set + through wl_data_offer.set_actions when handling an "ask" action. + + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. + + The most recent action received is always the valid one. Prior to + receiving wl_data_device.drop, the chosen action may change (e.g. + due to keyboard modifiers being pressed). At the time of receiving + wl_data_device.drop the drag-and-drop destination must honor the + last action received. + + Action changes may still happen after wl_data_device.drop, + especially on "ask" actions, where the drag-and-drop destination + may choose another action afterwards. Action changes happening + at this stage are always the result of inter-client negotiation, the + compositor shall no longer be able to induce a different action. + + Upon "ask" actions, it is expected that the drag-and-drop destination + may potentially choose different a different action and/or mime type, + based on wl_data_offer.source_actions and finally chosen by the + user (e.g. popping up a menu with the available options). The + final wl_data_offer.set_actions and wl_data_offer.accept requests + must happen before the call to wl_data_offer.finish. + </description> + <arg name="dnd_action" type="uint"/> + </event> </interface> <interface name="wl_data_source" version="3"> @@ -508,6 +603,13 @@ to requests to transfer the data. </description> + <enum name="error"> + <entry name="invalid_action_mask" value="0" + summary="action mask contains invalid values"/> + <entry name="invalid_source" value="1" + summary="source doesn't accept this request"/> + </enum> + <request name="offer"> <description summary="add an offered mime type"> This request adds a mime type to the set of mime types @@ -554,6 +656,9 @@ - The drag-and-drop operation was performed, but the drop destination did not accept any of the mimetypes offered through wl_data_source.target. + - The drag-and-drop operation was performed, but the drop destination + did not select any of the actions present in the mask offered through + wl_data_source.action. - The drag-and-drop operation was performed but didn't happen over a surface. - The compositor cancelled the drag-and-drop operation (e.g. compositor @@ -569,6 +674,25 @@ <!-- Version 3 additions --> + <request name="set_actions" since="3"> + <description summary="set the available drag-and-drop actions"> + Sets the actions that the source side client supports for this + operation. This request may trigger wl_data_source.action and + wl_data_offer.action events if the compositor needs to change the + selected action. + + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, otherwise it will result + in a protocol error. + + This request must be made once only, and can only be made on sources + used in drag-and-drop, so it must be performed before + wl_data_device.start_drag. Attempting to use the source other than + for drag-and-drop will raise a protocol error. + </description> + <arg name="dnd_actions" type="uint"/> + </request> + <event name="dnd_drop_performed" since="3"> <description summary="the drag-and-drop operation physically finished"> The user performed the drop action. This event does not indicate @@ -588,8 +712,42 @@ The drop destination finished interoperating with this data source, so the client is now free to destroy this data source and free all associated data. + + If the action used to perform the operation was "move", the + source can now delete the transferred data. </description> </event> + + <event name="action" since="3"> + <description summary="notify the selected action"> + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. + + This event can be emitted multiple times during the drag-and-drop + operation, mainly in response to destination side changes through + wl_data_offer.set_actions, and as the data device enters/leaves + surfaces. + + It is only possible to receive this event after + wl_data_source.dnd_drop_performed if the drag-and-drop operation + ended in an "ask" action, in which case the final wl_data_source.action + event will happen immediately before wl_data_source.dnd_finished. + + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. + + The most recent action received is always the valid one. The chosen + action may change alongside negotiation (e.g. an "ask" action can turn + into a "move" operation), so the effects of the final action must + always be applied in wl_data_offer.dnd_finished. + + Clients can trigger cursor surface changes from this point, so + they reflect the current action. + </description> + <arg name="dnd_action" type="uint"/> + </event> </interface> <interface name="wl_data_device" version="3"> @@ -705,6 +863,17 @@ <description summary="end drag-and-drag session successfully"> The event is sent when a drag-and-drop operation is ended because the implicit grab is removed. + + The drag-and-drop destination is expected to honor the last action + received through wl_data_offer.action, if the resulting action is + "copy" or "move", the destination can still perform + wl_data_offer.receive requests, and is expected to end all + transfers with a wl_data_offer.finish request. + + If the resulting action is "ask", the action will not be considered + final. The drag-and-drop destination is expected to perform one last + wl_data_offer.set_actions request, or wl_data_offer.destroy in order + to cancel the operation. </description> </event> @@ -757,6 +926,40 @@ <arg name="id" type="new_id" interface="wl_data_device"/> <arg name="seat" type="object" interface="wl_seat"/> </request> + + <!-- Version 3 additions --> + + <enum name="dnd_action" bitfield="true" since="3"> + <description summary="drag and drop actions"> + This is a bitmask of the available/preferred actions in a + drag-and-drop operation. + + In the compositor, the selected action is a result of matching the + actions offered by the source and destination sides. "action" events + with a "none" action will be sent to both source and destination if + there is no match. All further checks will effectively happen on + (source actions ∩ destination actions). + + In addition, compositors may also pick different actions in + reaction to key modifiers being pressed, one common design that + is used in major toolkits (and the behavior recommended for + compositors) is: + + - If no modifiers are pressed, the first match (in bit order) + will be used. + - Pressing Shift selects "move", if enabled in the mask. + - Pressing Control selects "copy", if enabled in the mask. + + Behavior beyond that is considered implementation-dependent. + Compositors may for example bind other modifiers (like Alt/Meta) + or drags initiated with other buttons than BTN_LEFT to specific + actions (e.g. "ask"). + </description> + <entry name="none" value="0"/> + <entry name="copy" value="1"/> + <entry name="move" value="2"/> + <entry name="ask" value="4"/> + </enum> </interface> <interface name="wl_shell" version="1"> From 0edeeb9cd5806959660af54d63fe9d402d50e6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Fri, 2 Oct 2015 11:12:02 +0800 Subject: [PATCH 0245/1152] client: Correct documentation regarding thread safeness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current documentation about wl_display_dispatch() states one may not mix wl_display_dispatch(_queue)() with wl_display_prepare_read() and friends, but this is a misconception about how wl_display_dispatch(_queue)() works. The fact is that the dispatch functions does the equivalent of what the preparation API does internally, and it is safe to use together. What is not safe is to dispatch using the wl_display_dispatch(_queue)() functions while being prepared to read using wl_display_read_events(). This patch rewrites the documentation to correctly state when the various API's are thread safe and how they may not be used. https://bugs.freedesktop.org/show_bug.cgi?id=91767 Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-client.c | 167 ++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 104 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 15eba6e4..cd94fd83 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -956,14 +956,13 @@ static const struct wl_callback_listener sync_listener = { * requests by sending a request to the display server and waiting for a * reply before returning. * + * This function uses wl_display_dispatch_queue() internally. It is not allowed + * to call this function while the thread is being prepared for reading events, + * and doing so will cause a dead lock. + * * \note This function may dispatch other events being received on the given * queue. * - * \note This function uses wl_display_dispatch_queue() internally. If you - * are using wl_display_read_events() from more threads, don't use this function - * (or make sure that calling wl_display_roundtrip_queue() doesn't interfere - * with calling wl_display_prepare_read() and wl_display_read_events()) - * * \sa wl_display_roundtrip() * \memberof wl_display */ @@ -997,14 +996,13 @@ wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *qu * requests by sending a request to the display server and waiting for a reply * before returning. * + * This function uses wl_display_dispatch_queue() internally. It is not allowed + * to call this function while the thread is being prepared for reading events, + * and doing so will cause a dead lock. + * * \note This function may dispatch other events being received on the default * queue. * - * \note This function uses wl_display_dispatch_queue() internally. If you - * are using wl_display_read_events() from more threads, don't use this function - * (or make sure that calling wl_display_roundtrip() doesn't interfere - * with calling wl_display_prepare_read() and wl_display_read_events()) - * * \memberof wl_display */ WL_EXPORT int @@ -1248,59 +1246,30 @@ cancel_read(struct wl_display *display) * \return 0 on success or -1 on error. In case of error errno will * be set accordingly * - * This will read events from the file descriptor for the display. - * This function does not dispatch events, it only reads and queues - * events into their corresponding event queues. If no data is - * available on the file descriptor, wl_display_read_events() returns - * immediately. To dispatch events that may have been queued, call + * Calling this function will result in data available on the display file + * descriptor being read and read events will be queued on their corresponding + * event queues. + * + * Before calling this function, depending on what thread it is to be called + * from, wl_display_prepare_read_queue() or wl_display_prepare_read() needs to + * be called. See wl_display_prepare_read_queue() for more details. + * + * When being called at a point where other threads have been prepared to read + * (using wl_display_prepare_read_queue() or wl_display_prepare_read()) this + * function will sleep until all other prepared threads have either been + * cancelled (using wl_display_cancel_read()) or them self entered this + * function. The last thread that calls this function will then read and queue + * events on their corresponding event queues, and finally wake up all other + * wl_display_read_events() calls causing them to return. + * + * If a thread cancels a read preparation when all other threads that have + * prepared to read has either called wl_display_cancel_read() or + * wl_display_read_events(), all reader threads will return without having read + * any data. + * + * To dispatch events that may have been queued, call * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending(). * - * Before calling this function, wl_display_prepare_read() must be - * called first. When running in more threads (which is the usual - * case, since we'd use wl_display_dispatch() otherwise), every thread - * must call wl_display_prepare_read() before calling this function. - * - * After calling wl_display_prepare_read() there can be some extra code - * before calling wl_display_read_events(), for example poll() or alike. - * Example of code in a thread: - * - * \code - * - * while (wl_display_prepare_read(display) < 0) - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * - * ... some code ... - * - * fds[0].fd = wl_display_get_fd(display); - * fds[0].events = POLLIN; - * poll(fds, 1, -1); - * - * if (!everything_ok()) { - * wl_display_cancel_read(display); - * handle_error(); - * } - * - * if (wl_display_read_events(display) < 0) - * handle_error(); - * - * ... - * \endcode - * - * After wl_display_prepare_read() succeeds, other threads that enter - * wl_display_read_events() will sleep until the very last thread enters - * it too or cancels. Therefore when the display fd becomes (or already - * is) readable, wl_display_read_events() should be called as soon as - * possible to unblock all threads. If wl_display_read_events() will not - * be called, then wl_display_cancel_read() must be called instead to let - * the other threads continue. - * - * This function must not be called simultaneously with wl_display_dispatch(). - * It may lead to deadlock. If programmer wants, for some reason, use - * wl_display_dispatch() in one thread and wl_display_prepare_read() with - * wl_display_read_events() in another, extra care must be taken to serialize - * these calls, i. e. use mutexes or similar (on whole prepare + read sequence) - * * \sa wl_display_prepare_read(), wl_display_cancel_read(), * wl_display_dispatch_pending(), wl_display_dispatch() * @@ -1401,28 +1370,6 @@ err: * to wl_display_prepare_read_queue() fails, we dispatch the pending events and * try again until we're successful. * - * When using wl_display_dispatch() we'd have something like: - * - * \code - * wl_display_dispatch_pending(display); - * wl_display_flush(display); - * poll(fds, nfds, -1); - * wl_display_dispatch(display); - * \endcode - * - * This sequence in not thread-safe. The race is immediately after poll(), - * where one thread could preempt and read events before the other thread calls - * wl_display_dispatch(). This call now blocks and starves the other - * fds in the event loop. - * - * Another race would be when using more event queues. - * When one thread calls wl_display_dispatch(_queue)(), then it - * reads all events from display's fd and queues them in appropriate - * queues. Then it dispatches only its own queue and the other events - * are sitting in their queues, waiting for dispatching. If that happens - * before the other thread managed to call poll(), it will - * block with events queued. - * * The wl_display_prepare_read_queue() function doesn't acquire exclusive access * to the display's fd. It only registers that the thread calling this function * has intention to read from fd. When all registered readers call @@ -1501,19 +1448,27 @@ wl_display_cancel_read(struct wl_display *display) * \param queue The event queue to dispatch * \return The number of dispatched events on success or -1 on failure * - * Dispatch all incoming events for objects assigned to the given - * event queue. On failure -1 is returned and errno set appropriately. + * Dispatch events on the given event queue. * - * The behaviour of this function is exactly the same as the behaviour of - * wl_display_dispatch(), but it dispatches events on given queue, - * not on the default queue. + * If the given event queue is empty, this function blocks until there are + * events to be read from the display fd. Events are read and queued on + * the appropriate event queues. Finally, events on given event queue are + * dispatched. On failure -1 is returned and errno set appropriately. * - * This function blocks if there are no events to dispatch (if there are, - * it only dispatches these events and returns immediately). - * When this function returns after blocking, it means that it read events - * from display's fd and queued them to appropriate queues. - * If among the incoming events were some events assigned to the given queue, - * they are dispatched by this moment. + * In a multi threaded enviroment, do not manually wait using poll() (or + * equivalent) before calling this function, as doing so might cause a dead + * lock. If external reliance on poll() (or equivalent) is required, see + * wl_display_prepare_read_queue() of how to do so. + * + * This function is thread safe as long as it dispatches the right queue on the + * right thread. It is also compatible with the multi thread event reading + * preparation API (see wl_display_prepare_read_queue()), and uses the + * equivalent functionality internally. It is not allowed to call this function + * while the thread is being prepared for reading events, and doing so will + * cause a dead lock. + * + * It can be used as a helper function to ease the procedure of reading and + * dispatching events. * * \note Since Wayland 1.5 the display has an extra queue * for its own events (i. e. delete_id). This queue is dispatched always, @@ -1521,11 +1476,8 @@ wl_display_cancel_read(struct wl_display *display) * That means that this function can return non-0 value even when it * haven't dispatched any event for the given queue. * - * This function has the same constrains for using in multi-threaded apps - * as \ref wl_display_dispatch(). - * * \sa wl_display_dispatch(), wl_display_dispatch_pending(), - * wl_display_dispatch_queue_pending() + * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue() * * \memberof wl_display */ @@ -1622,17 +1574,24 @@ wl_display_dispatch_queue_pending(struct wl_display *display, * \param display The display context object * \return The number of dispatched events on success or -1 on failure * - * Dispatch the display's default event queue. + * Dispatch events on the default event queue. * * If the default event queue is empty, this function blocks until there are * events to be read from the display fd. Events are read and queued on * the appropriate event queues. Finally, events on the default event queue - * are dispatched. + * are dispatched. On failure -1 is returned and errno set appropriately. * - * In multi-threaded environment, programmer may want to use - * wl_display_read_events(). However, use of wl_display_read_events() - * must not be mixed with wl_display_dispatch(). See wl_display_read_events() - * and wl_display_prepare_read() for more details. + * In a multi threaded enviroment, do not manually wait using poll() (or + * equivalent) before calling this function, as doing so might cause a dead + * lock. If external reliance on poll() (or equivalent) is required, see + * wl_display_prepare_read_queue() of how to do so. + * + * This function is thread safe as long as it dispatches the right queue on the + * right thread. It is also compatible with the multi thread event reading + * preparation API (see wl_display_prepare_read_queue()), and uses the + * equivalent functionality internally. It is not allowed to call this function + * while the thread is being prepared for reading events, and doing so will + * cause a dead lock. * * \note It is not possible to check if there are events on the queue * or not. For dispatching default queue events without blocking, see \ref From 0b44298a15674121ff54585c706bfdefc0d9942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Fri, 2 Oct 2015 11:18:12 +0800 Subject: [PATCH 0246/1152] client: Remove misplaced documentation about main loop intergration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was documentation about how to integrate the display server file descriptor in the documentation about wl_display_dispatch_pending(). This is not the right place to put it, and it also had incorrect usage of the API (calling wl_display_dispatch_queue() on input on an unrelated fd) as an example. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-client.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index cd94fd83..33eb2473 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1617,28 +1617,6 @@ wl_display_dispatch(struct wl_display *display) * attempt to read the display fd and simply returns zero if the main * queue is empty, i.e., it doesn't block. * - * This is necessary when a client's main loop wakes up on some fd other - * than the display fd (network socket, timer fd, etc) and calls \ref - * wl_display_dispatch_queue() from that callback. This may queue up - * events in other queues while reading all data from the display fd. - * When the main loop returns from the handler, the display fd - * no longer has data, causing a call to \em poll(2) (or similar - * functions) to block indefinitely, even though there are events ready - * to dispatch. - * - * To proper integrate the wayland display fd into a main loop, the - * client should always call wl_display_dispatch_pending() and then - * \ref wl_display_flush() prior to going back to sleep. At that point, - * the fd typically doesn't have data so attempting I/O could block, but - * events queued up on the default queue should be dispatched. - * - * A real-world example is a main loop that wakes up on a timerfd (or a - * sound card fd becoming writable, for example in a video player), which - * then triggers GL rendering and eventually eglSwapBuffers(). - * eglSwapBuffers() may call wl_display_dispatch_queue() if it didn't - * receive the frame event for the previous frame, and as such queue - * events in the default queue. - * * \sa wl_display_dispatch(), wl_display_dispatch_queue(), * wl_display_flush() * From c767f35b122737d282125f0b864caf552c21e0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 28 Dec 2015 14:35:50 +0800 Subject: [PATCH 0247/1152] client: Don't make EPIPE fatal if triggered when flushing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If flushing hits EPIPE it should not make it a fatal error since it would make it impossible to process the rest of the data available in the buffer. Instead, let reading the socket make EPIPE fatal, letting the client have the possibility to process the last messages including any error causing the termination. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-client.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 33eb2473..69f91a68 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1498,10 +1498,10 @@ wl_display_dispatch_queue(struct wl_display *display, return ret; } - /* We ignore EPIPE here, so that we try to read events before - * returning an error. When the compositor sends an error it - * will close the socket, and if we bail out here we don't get - * a chance to process the error. */ + /* We ignore EPIPE here, so that we try to read events before + * returning an error. When the compositor sends an error it + * will close the socket, and if we bail out here we don't get + * a chance to process the error. */ ret = wl_connection_flush(display->connection); if (ret < 0 && errno != EAGAIN && errno != EPIPE) { display_fatal_error(display, errno); @@ -1727,8 +1727,12 @@ wl_display_flush(struct wl_display *display) errno = display->last_error; ret = -1; } else { + /* We don't make EPIPE a fatal error here, so that we may try to + * read events after the failed flush. When the compositor sends + * an error it will close the socket, and if we make EPIPE fatal + * here we don't get a chance to process the error. */ ret = wl_connection_flush(display->connection); - if (ret < 0 && errno != EAGAIN) + if (ret < 0 && errno != EAGAIN && errno != EPIPE) display_fatal_error(display, errno); } From 689fff36ca7d2967b4f2724f731df1391df4f337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Fri, 2 Oct 2015 17:11:13 +0800 Subject: [PATCH 0248/1152] client: Use read preparation API in wl_display_dispatch_queue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of doing things that do the equivalent of using wl_display_prepare_read() and friends, just use the public API. The only semantical difference is that we will now unlock and lock the mutex more times compared to before. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-client.c | 45 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 69f91a68..18a837a6 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1488,30 +1488,17 @@ wl_display_dispatch_queue(struct wl_display *display, struct pollfd pfd[2]; int ret; - pthread_mutex_lock(&display->mutex); + if (wl_display_prepare_read_queue(display, queue) == -1) + return wl_display_dispatch_queue_pending(display, queue); - ret = dispatch_queue(display, queue); - if (ret == -1) - goto err_unlock; - if (ret > 0) { - pthread_mutex_unlock(&display->mutex); - return ret; - } - - /* We ignore EPIPE here, so that we try to read events before - * returning an error. When the compositor sends an error it - * will close the socket, and if we bail out here we don't get - * a chance to process the error. */ - ret = wl_connection_flush(display->connection); + /* Don't stop if flushing hits an EPIPE; continue so we can read any + * protocol error that may have triggered it. */ + ret = wl_display_flush(display); if (ret < 0 && errno != EAGAIN && errno != EPIPE) { - display_fatal_error(display, errno); - goto err_unlock; + wl_display_cancel_read(display); + return -1; } - display->reader_count++; - - pthread_mutex_unlock(&display->mutex); - pfd[0].fd = display->fd; pfd[0].events = POLLIN; do { @@ -1523,22 +1510,10 @@ wl_display_dispatch_queue(struct wl_display *display, return -1; } - pthread_mutex_lock(&display->mutex); + if (wl_display_read_events(display) == -1) + return -1; - if (read_events(display) == -1) - goto err_unlock; - - ret = dispatch_queue(display, queue); - if (ret == -1) - goto err_unlock; - - pthread_mutex_unlock(&display->mutex); - - return ret; - - err_unlock: - pthread_mutex_unlock(&display->mutex); - return -1; + return wl_display_dispatch_queue_pending(display, queue); } /** Dispatch pending events in an event queue From 242617c3161f7d50a592ab21607301aacd4e8f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 28 Dec 2015 14:50:12 +0800 Subject: [PATCH 0249/1152] client: Fully flush during blocking dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wl_display_flush() may fail with EAGAIN which means that not all data waiting in the buffer has been flushed. We later block until there is data to read, which could mean that we block on input from the compositor without having sent out all data from the client. Avoid this by fully flushing the socket before starting to wait. This commit also changes the array length of the struct pollfd array from 2 to 1, as only one element was ever used. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/wayland-client.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 18a837a6..55483c64 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1442,6 +1442,21 @@ wl_display_cancel_read(struct wl_display *display) pthread_mutex_unlock(&display->mutex); } +static int +wl_display_poll(struct wl_display *display, short int events) +{ + int ret; + struct pollfd pfd[1]; + + pfd[0].fd = display->fd; + pfd[0].events = events; + do { + ret = poll(pfd, 1, -1); + } while (ret == -1 && errno == EINTR); + + return ret; +} + /** Dispatch events in an event queue * * \param display The display context object @@ -1485,27 +1500,31 @@ WL_EXPORT int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue) { - struct pollfd pfd[2]; int ret; if (wl_display_prepare_read_queue(display, queue) == -1) return wl_display_dispatch_queue_pending(display, queue); + while (true) { + ret = wl_display_flush(display); + + if (ret != -1 || errno != EAGAIN) + break; + + if (wl_display_poll(display, POLLOUT) == -1) { + wl_display_cancel_read(display); + return -1; + } + } + /* Don't stop if flushing hits an EPIPE; continue so we can read any * protocol error that may have triggered it. */ - ret = wl_display_flush(display); - if (ret < 0 && errno != EAGAIN && errno != EPIPE) { + if (ret < 0 && errno != EPIPE) { wl_display_cancel_read(display); return -1; } - pfd[0].fd = display->fd; - pfd[0].events = POLLIN; - do { - ret = poll(pfd, 1, -1); - } while (ret == -1 && errno == EINTR); - - if (ret == -1) { + if (wl_display_poll(display, POLLIN) == -1) { wl_display_cancel_read(display); return -1; } From 7efe8fbd89b069947d616ba187732ce2c2804839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Thu, 24 Dec 2015 12:41:46 +0800 Subject: [PATCH 0250/1152] tests: Synchronize client termination in idle callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently wait for clients in the wl_client destroy signal, which is called before the client is destructed and the socket is closed. If test clients rely on being closed due to the socket being closed we'd dead lock. Avoid this by synchronizing in an idle task that is called after the client is fully destroyed. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- tests/test-compositor.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 296db3bb..965074bd 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -91,17 +91,13 @@ get_socket_name(void) return retval; } -/** - * Check client's state and terminate display when all clients exited - */ static void -client_destroyed(struct wl_listener *listener, void *data) +handle_client_destroy(void *data) { + struct client_info *ci = data; struct display *d; - struct client_info *ci; siginfo_t status; - ci = wl_container_of(listener, ci, destroy_listener); d = ci->display; assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1); @@ -132,6 +128,25 @@ client_destroyed(struct wl_listener *listener, void *data) * clients. In the case that the test would go through * the clients list manually, zero out the wl_client as a sign * that the client is not running anymore */ +} + +/** + * Check client's state and terminate display when all clients exited + */ +static void +client_destroyed(struct wl_listener *listener, void *data) +{ + struct client_info *ci; + struct display *d; + struct wl_event_loop *loop; + + /* Wait for client in an idle handler to avoid blocking the actual + * client destruction (fd close etc. */ + ci = wl_container_of(listener, ci, destroy_listener); + d = ci->display; + loop = wl_display_get_event_loop(d->wl_display); + wl_event_loop_add_idle(loop, handle_client_destroy, ci); + ci->wl_client = NULL; } From 046012a6cf1a50e1de2c73cf5a29098453b0171f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 28 Dec 2015 11:25:00 +0800 Subject: [PATCH 0251/1152] tests: Pass argument to client main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the API to pass an "void *" argument to the client main function, allowing the caller to call the same main function with different input. A helper (client_create_noarg) is added for when no argument is passed, and the existing test cases are changed to use this function instead. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- tests/connection-test.c | 4 ++-- tests/display-test.c | 24 ++++++++++++------------ tests/queue-test.c | 6 +++--- tests/sanity-test.c | 20 ++++++++++---------- tests/test-compositor.c | 17 +++++++++++------ tests/test-compositor.h | 11 +++++++---- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/tests/connection-test.c b/tests/connection-test.c index e9832b75..5d97fd98 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -614,7 +614,7 @@ TEST(closure_leaks) { struct display *d = display_create(); - client_create(d, leak_closure); + client_create_noarg(d, leak_closure); display_run(d); display_destroy(d); @@ -645,7 +645,7 @@ TEST(closure_leaks_after_error) struct display *d = display_create(); struct client_info *cl; - cl = client_create(d, leak_after_error); + cl = client_create_noarg(d, leak_after_error); display_run(d); wl_client_post_no_memory(cl->wl_client); diff --git a/tests/display-test.c b/tests/display-test.c index 161a4028..f931c13b 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -95,7 +95,7 @@ empty_client(void) TEST(tc_leaks_tests) { struct display *d = display_create(); - client_create(d, empty_client); + client_create_noarg(d, empty_client); display_run(d); display_destroy(d); } @@ -209,7 +209,7 @@ TEST(post_error_to_one_client) wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); - cl = client_create(d, post_error_main); + cl = client_create_noarg(d, post_error_main); display_run(d); /* the display was stopped by client, so it can @@ -264,8 +264,8 @@ TEST(post_error_to_one_from_two_clients) wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); - client_create(d, post_error_main2); - cl = client_create(d, post_error_main3); + client_create_noarg(d, post_error_main2); + cl = client_create_noarg(d, post_error_main3); display_run(d); /* post error only to the second client */ @@ -289,8 +289,8 @@ TEST(post_error_to_two_clients) wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); - cl = client_create(d, post_error_main3); - cl2 = client_create(d, post_error_main3); + cl = client_create_noarg(d, post_error_main3); + cl2 = client_create_noarg(d, post_error_main3); display_run(d); @@ -331,7 +331,7 @@ TEST(post_nomem_tst) wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); - cl = client_create(d, post_nomem_main); + cl = client_create_noarg(d, post_nomem_main); display_run(d); assert(cl->data); @@ -340,7 +340,7 @@ TEST(post_nomem_tst) /* first client terminated. Run it again, * but post no memory to client */ - cl = client_create(d, post_nomem_main); + cl = client_create_noarg(d, post_nomem_main); display_run(d); assert(cl->data); @@ -447,7 +447,7 @@ TEST(threading_errors_tst) { struct display *d = display_create(); - client_create(d, threading_post_err); + client_create_noarg(d, threading_post_err); display_run(d); display_destroy(d); @@ -502,7 +502,7 @@ TEST(threading_cancel_read_tst) { struct display *d = display_create(); - client_create(d, threading_cancel_read); + client_create_noarg(d, threading_cancel_read); display_run(d); display_destroy(d); @@ -542,7 +542,7 @@ threading_read_eagain(void) TEST(threading_read_eagain_tst) { struct display *d = display_create(); - client_create(d, threading_read_eagain); + client_create_noarg(d, threading_read_eagain); display_run(d); @@ -604,7 +604,7 @@ TEST(threading_read_after_error_tst) { struct display *d = display_create(); - client_create(d, threading_read_after_error); + client_create_noarg(d, threading_read_after_error); display_run(d); display_destroy(d); diff --git a/tests/queue-test.c b/tests/queue-test.c index dc1a01db..02865aec 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -230,7 +230,7 @@ TEST(queue_proxy_destroy) test_set_timeout(2); - client_create(d, client_test_proxy_destroy); + client_create_noarg(d, client_test_proxy_destroy); display_run(d); display_destroy(d); @@ -242,7 +242,7 @@ TEST(queue_multiple_queues) test_set_timeout(2); - client_create(d, client_test_multiple_queues); + client_create_noarg(d, client_test_multiple_queues); display_run(d); display_destroy(d); @@ -254,7 +254,7 @@ TEST(queue_roundtrip) test_set_timeout(2); - client_create(d, client_test_queue_roundtrip); + client_create_noarg(d, client_test_queue_roundtrip); display_run(d); display_destroy(d); diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 65d986dc..7a93da32 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -119,7 +119,7 @@ FAIL_TEST(sanity_malloc_indirect) FAIL_TEST(tc_client_memory_leaks) { struct display *d = display_create(); - client_create(d, sanity_malloc_direct); + client_create_noarg(d, sanity_malloc_direct); display_run(d); display_destroy(d); } @@ -127,7 +127,7 @@ FAIL_TEST(tc_client_memory_leaks) FAIL_TEST(tc_client_memory_leaks2) { struct display *d = display_create(); - client_create(d, sanity_malloc_indirect); + client_create_noarg(d, sanity_malloc_indirect); display_run(d); display_destroy(d); } @@ -195,11 +195,11 @@ TEST(tc_client_no_fd_leaks) struct display *d = display_create(); /* Client which does not consume the WAYLAND_DISPLAY socket. */ - client_create(d, sanity_fd_no_leak); + client_create_noarg(d, sanity_fd_no_leak); display_run(d); /* Client which does consume the WAYLAND_DISPLAY socket. */ - client_create(d, sanity_client_no_leak); + client_create_noarg(d, sanity_client_no_leak); display_run(d); display_destroy(d); @@ -209,7 +209,7 @@ FAIL_TEST(tc_client_fd_leaks) { struct display *d = display_create(); - client_create(d, sanity_fd_leak); + client_create_noarg(d, sanity_fd_leak); display_run(d); display_destroy(d); @@ -219,7 +219,7 @@ FAIL_TEST(tc_client_fd_leaks_exec) { struct display *d = display_create(); - client_create(d, sanity_fd_leak); + client_create_noarg(d, sanity_fd_leak); display_run(d); display_destroy(d); @@ -263,7 +263,7 @@ TEST(timeout_turnoff) FAIL_TEST(tc_timeout_tst) { struct display *d = display_create(); - client_create(d, timeout_tst); + client_create_noarg(d, timeout_tst); display_run(d); display_destroy(d); } @@ -271,7 +271,7 @@ FAIL_TEST(tc_timeout_tst) FAIL_TEST(tc_timeout2_tst) { struct display *d = display_create(); - client_create(d, timeout_reset_tst); + client_create_noarg(d, timeout_reset_tst); display_run(d); display_destroy(d); } @@ -280,10 +280,10 @@ TEST(tc_timeout3_tst) { struct display *d = display_create(); - client_create(d, timeout2_tst); + client_create_noarg(d, timeout2_tst); display_run(d); - client_create(d, timeout_turnoff); + client_create_noarg(d, timeout_turnoff); display_run(d); display_destroy(d); diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 965074bd..b01e8afe 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -151,7 +151,8 @@ client_destroyed(struct wl_listener *listener, void *data) } static void -run_client(void (*client_main)(void), int wayland_sock, int client_pipe) +run_client(void (*client_main)(void *data), void *data, + int wayland_sock, int client_pipe) { char s[8]; int cur_alloc, cur_fds; @@ -170,7 +171,7 @@ run_client(void (*client_main)(void), int wayland_sock, int client_pipe) cur_alloc = get_current_alloc_num(); cur_fds = count_open_fds(); - client_main(); + client_main(data); /* Clients using wl_display_connect() will end up closing the socket * passed in through the WAYLAND_SOCKET environment variable. When @@ -185,7 +186,8 @@ run_client(void (*client_main)(void), int wayland_sock, int client_pipe) static struct client_info * display_create_client(struct display *d, - void (*client_main)(void), + void (*client_main)(void *data), + void *data, const char *name) { int pipe_cli[2]; @@ -205,7 +207,7 @@ display_create_client(struct display *d, close(sock_wayl[1]); close(pipe_cli[1]); - run_client(client_main, sock_wayl[0], pipe_cli[0]); + run_client(client_main, data, sock_wayl[0], pipe_cli[0]); close(sock_wayl[0]); close(pipe_cli[0]); @@ -246,11 +248,14 @@ display_create_client(struct display *d, } struct client_info * -client_create_with_name(struct display *d, void (*client_main)(void), +client_create_with_name(struct display *d, + void (*client_main)(void *data), void *data, const char *name) { int can_continue = 1; - struct client_info *cl = display_create_client(d, client_main, name); + struct client_info *cl = display_create_client(d, + client_main, data, + name); /* let the show begin! */ assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int)); diff --git a/tests/test-compositor.h b/tests/test-compositor.h index c97eb96d..526e9123 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -78,8 +78,8 @@ int stop_display(struct client *, int); * wl_global_create(d->wl_display, ...); * ... other setups ... * - * client_create(d, client_main); - * client_create(d, client_main2); + * client_create(d, client_main, data); + * client_create(d, client_main2, data); * * display_run(d); * display_destroy(d); @@ -95,6 +95,9 @@ void display_run(struct display *d); void display_resume(struct display *d); struct client_info *client_create_with_name(struct display *d, - void (*client_main)(void), + void (*client_main)(void *data), + void *data, const char *name); -#define client_create(d, c) client_create_with_name((d), (c), (#c)) +#define client_create(d, c, data) client_create_with_name((d), (c), data, (#c)) +#define client_create_noarg(d, c) \ + client_create_with_name((d), (void(*)(void *)) (c), NULL, (#c)) From c6437817dd9bbb2fd1027a103e77e238ad5e5ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 28 Dec 2015 14:33:36 +0800 Subject: [PATCH 0252/1152] tests: Test that one can fetch the protocol error after EPIPE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a client is terminated due to some reason, it should always be possible to retrieve protocol error associated with the termination. Test that, while either using the dispatch helpers (wl_display_dispatch(_queue)() or the prepare read API, it should be possible to retrieve the error after EPIPE. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- tests/display-test.c | 180 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 10 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index f931c13b..0d25ca37 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -24,6 +24,7 @@ * SOFTWARE. */ +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -35,6 +36,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <pthread.h> +#include <poll.h> #include "wayland-private.h" #include "wayland-server.h" @@ -135,15 +137,12 @@ client_get_seat(struct client *c) } static void -check_for_error(struct client *c, struct wl_proxy *proxy) +check_pending_error(struct client *c, struct wl_proxy *proxy) { uint32_t ec, id; int err; const struct wl_interface *intf; - /* client should be disconnected */ - assert(wl_display_roundtrip(c->wl_display) == -1); - err = wl_display_get_error(c->wl_display); assert(err == EPROTO); @@ -153,6 +152,30 @@ check_for_error(struct client *c, struct wl_proxy *proxy) assert(id == wl_proxy_get_id(proxy)); } +static void +check_for_error(struct client *c, struct wl_proxy *proxy) +{ + /* client should be disconnected */ + assert(wl_display_roundtrip(c->wl_display) == -1); + + check_pending_error(c, proxy); +} + +static struct client_info * +find_client_info(struct display *d, struct wl_client *client) +{ + struct client_info *ci; + + /* find the right client_info struct and save the + * resource as its data, so that we can use it later */ + wl_list_for_each(ci, &d->clients, link) { + if (ci->wl_client == client) + return ci; + } + + return NULL; +} + static void bind_seat(struct wl_client *client, void *data, uint32_t vers, uint32_t id) @@ -161,12 +184,8 @@ bind_seat(struct wl_client *client, void *data, struct client_info *ci; struct wl_resource *res; - /* find the right client_info struct and save the - * resource as its data, so that we can use it later */ - wl_list_for_each(ci, &d->clients, link) { - if (ci->wl_client == client) - break; - } + ci = find_client_info(d, client); + assert(ci); res = wl_resource_create(client, &wl_seat_interface, vers, id); assert(res); @@ -609,3 +628,144 @@ TEST(threading_read_after_error_tst) display_destroy(d); } + +static void +wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy) +{ + int ret; + + while (true) { + /* Dispatching should eventually hit the protocol error before + * any other error. */ + ret = wl_display_dispatch(c->wl_display); + if (ret == 0) { + continue; + } else { + assert(errno == EPROTO); + break; + } + } + + check_pending_error(c, proxy); +} + +static void +wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy) +{ + int ret = 0; + struct pollfd pfd[2]; + + while (true) { + while (wl_display_prepare_read(c->wl_display) != 0 && + errno == EAGAIN) { + assert(wl_display_dispatch_pending(c->wl_display) >= 0); + } + + /* Flush may fail due to EPIPE if the connection is broken, but + * this must not set a fatal display error because that would + * result in it being impossible to read a potential protocol + * error. */ + do { + ret = wl_display_flush(c->wl_display); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + assert(ret >= 0 || errno == EPIPE); + assert(wl_display_get_error(c->wl_display) == 0); + + pfd[0].fd = wl_display_get_fd(c->wl_display); + pfd[0].events = POLLIN; + do { + ret = poll(pfd, 1, -1); + } while (ret == -1 && errno == EINTR); + assert(ret != -1); + + /* We should always manage to read the error before the EPIPE + * comes this way. */ + assert(wl_display_read_events(c->wl_display) == 0); + + /* Dispatching should eventually hit the protocol error before + * any other error. */ + ret = wl_display_dispatch_pending(c->wl_display); + if (ret == 0) { + continue; + } else { + assert(errno == EPROTO); + break; + } + } + + check_pending_error(c, proxy); +} + +static void +check_error_after_epipe(void *data) +{ + bool use_dispatch_helpers = *(bool *) data; + struct client *client; + struct wl_seat *seat; + struct wl_callback *callback; + + client = client_connect(); + + /* This will, according to the implementation below, cause the server + * to post an error. */ + seat = client_get_seat(client); + wl_display_flush(client->wl_display); + + /* The server will not actually destroy the client until it receives + * input, so send something to trigger the client destruction. */ + callback = wl_display_sync(client->wl_display); + wl_callback_destroy(callback); + + /* Sleep some to give the server a chance to react and destroy the + * client. */ + test_usleep(200000); + + /* Wait for the protocol error and check that we reached it before + * EPIPE. */ + if (use_dispatch_helpers) { + wait_for_error_using_dispatch(client, (struct wl_proxy *) seat); + } else { + wait_for_error_using_prepare_read(client, + (struct wl_proxy *) seat); + } + + wl_seat_destroy(seat); + client_disconnect_nocheck(client); +} + +static void +bind_seat_and_post_error(struct wl_client *client, void *data, + uint32_t version, uint32_t id) +{ + struct display *d = data; + struct client_info *ci; + struct wl_resource *resource; + + ci = find_client_info(d, client); + assert(ci); + + resource = wl_resource_create(client, &wl_seat_interface, version, id); + assert(resource); + ci->data = resource; + + wl_resource_post_error(ci->data, 23, "Dummy error"); +} + +TEST(error_code_after_epipe) +{ + struct display *d = display_create(); + bool use_dispatch_helpers; + + wl_global_create(d->wl_display, &wl_seat_interface, + 1, d, bind_seat_and_post_error); + + use_dispatch_helpers = true; + client_create(d, check_error_after_epipe, &use_dispatch_helpers); + display_run(d); + + use_dispatch_helpers = false; + client_create(d, check_error_after_epipe, &use_dispatch_helpers); + display_run(d); + + display_destroy(d); +} From 557032e36cf5c45ec1a827f2ec49bdcce3833e80 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand <jason@jlekstrand.net> Date: Thu, 12 Nov 2015 13:53:15 -0600 Subject: [PATCH 0253/1152] Track protocol object versions inside wl_proxy. This provides a standardized mechanism for tracking protocol object versions in client code. The wl_display object is created with version 1. Every time an object is created from within wl_registry_bind, it gets the bound version. Every other time an object is created, it simply inherits it's version from the parent object that created it. (comments and minor reformatting added by Derek Foreman <derekf@osg.samsung.com>) Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Second trivial commit squashed into this one: Authored by Derek Foreman <derekf@osg.samsung.com> Signed-off-by: Derek Foreman <derekf@osg.samsung.com> (it's literally one of code and a lot of comments) This sets wl_display's version (for proxy version query purposes) to 0. Any proxy created with unversioned API (this happens when a client compiled with old headers links against new wayland) will inherit this 0. This gives us a way for new libraries linked by old clients to realize they can't know a proxy's version. wl_display's version being unqueryable (always returning 0) is an acceptable side effect, since it's a special object you can't bind specific versions of anyway. Second half: Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Jason Ekstrand <jason@jlekstrand.net> --- src/scanner.c | 34 +++++++--- src/wayland-client-core.h | 15 ++++ src/wayland-client.c | 139 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 173 insertions(+), 15 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index b00f036a..1d626f41 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -956,6 +956,14 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) interface->name, interface->name, interface->name, interface->name); + printf("static inline uint32_t\n" + "%s_get_version(struct %s *%s)\n" + "{\n" + "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n" + "}\n\n", + interface->name, interface->name, interface->name, + interface->name); + has_destructor = 0; has_destroy = 0; wl_list_for_each(m, message_list, link) { @@ -1027,21 +1035,31 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) printf(")\n" "{\n"); - if (ret) { + if (ret && ret->interface_name == NULL) { + /* an arg has type ="new_id" but interface is not + * provided, such as in wl_registry.bind */ printf("\tstruct wl_proxy *%s;\n\n" - "\t%s = wl_proxy_marshal_constructor(" + "\t%s = wl_proxy_marshal_constructor_versioned(" "(struct wl_proxy *) %s,\n" - "\t\t\t %s_%s, ", + "\t\t\t %s_%s, interface, version", ret->name, ret->name, interface->name, interface->uppercase_name, m->uppercase_name); - - if (ret->interface_name == NULL) - printf("interface"); - else - printf("&%s_interface", ret->interface_name); + } else if (ret) { + /* Normal factory case, an arg has type="new_id" and + * an interface is provided */ + printf("\tstruct wl_proxy *%s;\n\n" + "\t%s = wl_proxy_marshal_constructor(" + "(struct wl_proxy *) %s,\n" + "\t\t\t %s_%s, &%s_interface", + ret->name, ret->name, + interface->name, + interface->uppercase_name, + m->uppercase_name, + ret->interface_name); } else { + /* No args have type="new_id" */ printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n" "\t\t\t %s_%s", interface->name, diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index a7293952..91f7e7b8 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -139,9 +139,21 @@ wl_proxy_marshal_constructor(struct wl_proxy *proxy, ...); struct wl_proxy * +wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + ...); +struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface); +struct wl_proxy * +wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, + uint32_t opcode, + union wl_argument *args, + const struct wl_interface *interface, + uint32_t version); void wl_proxy_destroy(struct wl_proxy *proxy); @@ -164,6 +176,9 @@ wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); void * wl_proxy_get_user_data(struct wl_proxy *proxy); +uint32_t +wl_proxy_get_version(struct wl_proxy *proxy); + uint32_t wl_proxy_get_id(struct wl_proxy *proxy); diff --git a/src/wayland-client.c b/src/wayland-client.c index 55483c64..ef12bfcc 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -62,6 +62,7 @@ struct wl_proxy { int refcount; void *user_data; wl_dispatcher_func_t dispatcher; + uint32_t version; }; struct wl_global { @@ -326,7 +327,8 @@ wl_display_create_queue(struct wl_display *display) } static struct wl_proxy * -proxy_create(struct wl_proxy *factory, const struct wl_interface *interface) +proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, + uint32_t version) { struct wl_proxy *proxy; struct wl_display *display = factory->display; @@ -339,6 +341,7 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface) proxy->display = display; proxy->queue = factory->queue; proxy->refcount = 1; + proxy->version = version; proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy); @@ -371,7 +374,7 @@ wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface) struct wl_proxy *proxy; pthread_mutex_lock(&display->mutex); - proxy = proxy_create(factory, interface); + proxy = proxy_create(factory, interface, factory->version); pthread_mutex_unlock(&display->mutex); return proxy; @@ -394,6 +397,7 @@ wl_proxy_create_for_id(struct wl_proxy *factory, proxy->display = display; proxy->queue = factory->queue; proxy->refcount = 1; + proxy->version = factory->version; wl_map_insert_at(&display->objects, 0, id, proxy); @@ -525,7 +529,7 @@ wl_proxy_add_dispatcher(struct wl_proxy *proxy, static struct wl_proxy * create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, union wl_argument *args, - const struct wl_interface *interface) + const struct wl_interface *interface, uint32_t version) { int i, count; const char *signature; @@ -539,7 +543,7 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, switch (arg.type) { case 'n': - new_proxy = proxy_create(proxy, interface); + new_proxy = proxy_create(proxy, interface, version); if (new_proxy == NULL) return NULL; @@ -564,7 +568,8 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned - * on success or NULL on errror with errno set accordingly. + * on success or NULL on errror with errno set accordingly. The newly + * created proxy will inherit their version from their parent. * * \note This is intended to be used by language bindings and not in * non-generated code. @@ -577,6 +582,43 @@ WL_EXPORT struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface) +{ + return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, + args, interface, + proxy->version); +} + + +/** Prepare a request to be sent to the compositor + * + * \param proxy The proxy object + * \param opcode Opcode of the request to be sent + * \param args Extra arguments for the given request + * \param interface The interface to use for the new proxy + * \param version The protocol object version for the new proxy + * + * Translates the request given by opcode and the extra arguments into the + * wire format and write it to the connection buffer. This version takes an + * array of the union type wl_argument. + * + * For new-id arguments, this function will allocate a new wl_proxy + * and send the ID to the server. The new wl_proxy will be returned + * on success or NULL on errror with errno set accordingly. The newly + * created proxy will have the version specified. + * + * \note This is intended to be used by language bindings and not in + * non-generated code. + * + * \sa wl_proxy_marshal() + * + * \memberof wl_proxy + */ +WL_EXPORT struct wl_proxy * +wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, + uint32_t opcode, + union wl_argument *args, + const struct wl_interface *interface, + uint32_t version) { struct wl_closure *closure; struct wl_proxy *new_proxy = NULL; @@ -587,7 +629,8 @@ wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, message = &proxy->object.interface->methods[opcode]; if (interface) { new_proxy = create_outgoing_proxy(proxy, message, - args, interface); + args, interface, + version); if (new_proxy == NULL) goto err_unlock; } @@ -655,7 +698,8 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned - * on success or NULL on errror with errno set accordingly. + * on success or NULL on errror with errno set accordingly. The newly + * created proxy will inherit their version from their parent. * * \note This should not normally be used by non-generated code. * @@ -677,6 +721,46 @@ wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, args, interface); } + +/** Prepare a request to be sent to the compositor + * + * \param proxy The proxy object + * \param opcode Opcode of the request to be sent + * \param interface The interface to use for the new proxy + * \param version The protocol object version of the new proxy + * \param ... Extra arguments for the given request + * \return A new wl_proxy for the new_id argument or NULL on error + * + * Translates the request given by opcode and the extra arguments into the + * wire format and write it to the connection buffer. + * + * For new-id arguments, this function will allocate a new wl_proxy + * and send the ID to the server. The new wl_proxy will be returned + * on success or NULL on errror with errno set accordingly. The newly + * created proxy will have the version specified. + * + * \note This should not normally be used by non-generated code. + * + * \memberof wl_proxy + */ +WL_EXPORT struct wl_proxy * +wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, ...) +{ + union wl_argument args[WL_CLOSURE_MAX_ARGS]; + va_list ap; + + va_start(ap, version); + wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, + args, WL_CLOSURE_MAX_ARGS, ap); + va_end(ap); + + return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, + args, interface, + version); +} + /** Prepare a request to be sent to the compositor * * \param proxy The proxy object @@ -839,6 +923,25 @@ wl_display_connect_to_fd(int fd) display->proxy.flags = 0; display->proxy.refcount = 1; + /* We set this version to 0 for backwards compatibility. + * + * If a client is using old versions of protocol headers, + * it will use unversioned API to create proxies. Those + * proxies will inherit this 0. + * + * A client could be passing these proxies into library + * code newer than the headers that checks proxy + * versions. When the proxy version is reported as 0 + * the library will know that it can't reliably determine + * the proxy version, and should do whatever fallback is + * required. + * + * This trick forces wl_display to always report 0, but + * since it's a special object that we can't bind + * specific versions of anyway, this should be fine. + */ + display->proxy.version = 0; + display->connection = wl_connection_create(display->fd); if (display->connection == NULL) goto err_connection; @@ -1764,6 +1867,28 @@ wl_proxy_get_user_data(struct wl_proxy *proxy) return proxy->user_data; } +/** Get the protocol object version of a proxy object + * + * \param proxy The proxy object + * \return The protocol object version of the proxy or 0 + * + * Gets the protocol object version of a proxy object, or 0 + * if the proxy was created with unversioned API. + * + * A returned value of 0 means that no version information is + * available, so the caller must make safe assumptions about + * the object's real version. + * + * wl_display's version will always return 0. + * + * \memberof wl_proxy + */ +WL_EXPORT uint32_t +wl_proxy_get_version(struct wl_proxy *proxy) +{ + return proxy->version; +} + /** Get the id of a proxy object * * \param proxy The proxy object From e9d894204b1a424ff999acbfd28a933478bd6531 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Tue, 12 Jan 2016 16:15:04 -0600 Subject: [PATCH 0254/1152] tests: Test proxy versions Add a test that confirms that proxy versions are always 0 for display and correct otherwise. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- tests/display-test.c | 125 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 9 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index 0d25ca37..1a6c3456 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -37,6 +37,7 @@ #include <sys/stat.h> #include <pthread.h> #include <poll.h> +#include <stdbool.h> #include "wayland-private.h" #include "wayland-server.h" @@ -102,16 +103,48 @@ TEST(tc_leaks_tests) display_destroy(d); } +/* This is how pre proxy-version registry binds worked, + * this should create a proxy that shares the display's + * version number: 0 */ +static void * +old_registry_bind(struct wl_registry *wl_registry, + uint32_t name, + const struct wl_interface *interface, + uint32_t version) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor( + (struct wl_proxy *) wl_registry, WL_REGISTRY_BIND, + interface, name, interface->name, version, NULL); + + return (void *) id; +} + +struct handler_info { + struct wl_seat *seat; + uint32_t bind_version; + bool use_unversioned; +}; + static void registry_handle_globals(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { - struct wl_seat **seat = data; + struct handler_info *hi = data; + + /* This is only for the proxy version test */ + if (hi->bind_version) + ver = hi->bind_version; if (strcmp(intf, "wl_seat") == 0) { - *seat = wl_registry_bind(registry, id, - &wl_seat_interface, ver); - assert(*seat); + if (hi->use_unversioned) + hi->seat = old_registry_bind(registry, id, + &wl_seat_interface, ver); + else + hi->seat = wl_registry_bind(registry, id, + &wl_seat_interface, ver); + assert(hi->seat); } } @@ -121,19 +154,31 @@ static const struct wl_registry_listener registry_listener = { }; static struct wl_seat * -client_get_seat(struct client *c) +client_get_seat_with_info(struct client *c, struct handler_info *hi) { - struct wl_seat *seat; struct wl_registry *reg = wl_display_get_registry(c->wl_display); assert(reg); - wl_registry_add_listener(reg, ®istry_listener, &seat); + assert(hi); + hi->seat = NULL; + wl_registry_add_listener(reg, ®istry_listener, hi); wl_display_roundtrip(c->wl_display); - assert(seat); + assert(hi->seat); wl_registry_destroy(reg); - return seat; + return hi->seat; +} + +static struct wl_seat * +client_get_seat(struct client *c) +{ + struct handler_info hi; + + hi.use_unversioned = false; + hi.bind_version = 0; + + return client_get_seat_with_info(c, &hi); } static void @@ -769,3 +814,65 @@ TEST(error_code_after_epipe) display_destroy(d); } + +static void +check_seat_versions(struct wl_seat *seat, uint32_t ev) +{ + struct wl_pointer *pointer; + + assert(wl_proxy_get_version((struct wl_proxy *) seat) == ev); + assert(wl_seat_get_version(seat) == ev); + + pointer = wl_seat_get_pointer(seat); + assert(wl_pointer_get_version(pointer) == ev); + assert(wl_proxy_get_version((struct wl_proxy *) pointer) == ev); + wl_proxy_destroy((struct wl_proxy *) pointer); +} + +/* Normal client with proxy versions available. */ +static void +seat_version(void *data) +{ + struct handler_info *hi = data; + struct client *c = client_connect(); + struct wl_seat *seat; + + /* display proxy should always be version 0 */ + assert(wl_proxy_get_version((struct wl_proxy *) c->wl_display) == 0); + + seat = client_get_seat_with_info(c, hi); + if (hi->use_unversioned) + check_seat_versions(seat, 0); + else + check_seat_versions(seat, hi->bind_version); + + wl_proxy_destroy((struct wl_proxy *) seat); + + client_disconnect_nocheck(c); +} + +TEST(versions) +{ + struct display *d = display_create(); + struct wl_global *global; + int i; + + global = wl_global_create(d->wl_display, &wl_seat_interface, + 5, d, bind_seat); + + for (i = 1; i <= 5; i++) { + struct handler_info hi; + + hi.bind_version = i; + hi.use_unversioned = false; + client_create(d, seat_version, &hi); + hi.use_unversioned = true; + client_create(d, seat_version, &hi); + } + + display_run(d); + + wl_global_destroy(global); + + display_destroy(d); +} From 7ed00c1de77afbab23f4908fbd9d60ec070c209b Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 19 Jan 2016 14:30:33 -0800 Subject: [PATCH 0255/1152] configure.ac: bump to version 1.9.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 48658cf8..16735fb6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [9]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From eb52bb8e14f4d1ed3564abbb48ef3ddd28b115c0 Mon Sep 17 00:00:00 2001 From: Sung-Jin Park <input.hacker@gmail.com> Date: Thu, 14 Jan 2016 16:03:43 +0900 Subject: [PATCH 0256/1152] server: Add an API to get the file descriptor for a client This adds an API to get the file descriptor for a client. The client file descriptor can be used for a wayland compositor to validate a request from a client if there are any additional information provided from the client's file descriptor. For instance, this will be helpful in some linux distributions, in which SELinux or SMACK is enabled. In those environments, each file (including socket) will have each security contexts in its inode as xattr member variable. A wayland compositor can validate a client request by getting the file descriptor of the client and by checking the security contexts associated with the file descriptor. Signed-off-by: Sung-Jin Park <input.hacker@gmail.com> --- src/connection.c | 6 ++++++ src/wayland-private.h | 3 +++ src/wayland-server-core.h | 3 +++ src/wayland-server.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/src/connection.c b/src/connection.c index bc373f6b..65b64e9d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -405,6 +405,12 @@ wl_message_count_arrays(const struct wl_message *message) return arrays; } +int +wl_connection_get_fd(struct wl_connection *connection) +{ + return connection->fd; +} + static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { diff --git a/src/wayland-private.h b/src/wayland-private.h index da578d16..994bc453 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -136,6 +136,9 @@ int wl_connection_queue(struct wl_connection *connection, const void *data, size_t count); +int +wl_connection_get_fd(struct wl_connection *connection); + struct wl_closure { int count; const struct wl_message *message; diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 1700cd34..e8e1e9c2 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -182,6 +182,9 @@ void wl_client_get_credentials(struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid); +int +wl_client_get_fd(struct wl_client *client); + void wl_client_add_destroy_listener(struct wl_client *client, struct wl_listener *listener); diff --git a/src/wayland-server.c b/src/wayland-server.c index 3a7d79dd..6654cd7f 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -491,6 +491,41 @@ wl_client_get_credentials(struct wl_client *client, *gid = client->ucred.gid; } +/** Get the file descriptor for the client + * + * \param client The display object + * \return The file descriptor to use for the connection + * + * This function returns the file descriptor for the given client. + * + * Be sure to use the file descriptor from the client for inspection only. + * If the caller does anything to the file descriptor that changes its state, + * it will likely cause problems. + * + * See also wl_client_get_credentials(). + * It is recommended that you evaluate whether wl_client_get_credentials() + * can be applied to your use case instead of this function. + * + * If you would like to distinguish just between the client and the compositor + * itself from the client's request, it can be done by getting the client + * credentials and by checking the PID of the client and the compositor's PID. + * Regarding the case in which the socketpair() is being used, you need to be + * careful. Please note the documentation for wl_client_get_credentials(). + * + * This function can be used for a compositor to validate a request from + * a client if there are additional information provided from the client's + * file descriptor. For instance, suppose you can get the security contexts + * from the client's file descriptor. The compositor can validate the client's + * request with the contexts and make a decision whether it permits or deny it. + * + * \memberof wl_client + */ +WL_EXPORT int +wl_client_get_fd(struct wl_client *client) +{ + return wl_connection_get_fd(client->connection); +} + /** Look up an object in the client name space * * \param client The client object From 14b76a0e24c988334c18f477572a556ba005b182 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 19 Jan 2016 14:54:32 -0800 Subject: [PATCH 0257/1152] configure.ac: re-bump to version 1.9.91 for the alpha release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 16735fb6..2469cdb3 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.64]) -m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [9]) +m4_define([wayland_major_version], [1]) +m4_define([wayland_minor_version], [9]) m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From ac36082813c459e64ae1f564002a7cadfa0a7637 Mon Sep 17 00:00:00 2001 From: Sergi Granell <xerpi.g.12@gmail.com> Date: Mon, 1 Feb 2016 19:35:51 +0100 Subject: [PATCH 0258/1152] server: Fix possible wl_display_add_socket_fd memleak If wl_event_loop_add_fd failed, the fail path didn't free the newly allocated struct wl_socket. Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/wayland-server.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 6654cd7f..3ba8a5dd 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1268,17 +1268,18 @@ wl_display_add_socket_fd(struct wl_display *display, int sock_fd) if (s == NULL) return -1; - /* Reuse the existing fd */ - s->fd = sock_fd; - - s->source = wl_event_loop_add_fd(display->loop, s->fd, + s->source = wl_event_loop_add_fd(display->loop, sock_fd, WL_EVENT_READABLE, socket_data, display); if (s->source == NULL) { wl_log("failed to establish event source\n"); + wl_socket_destroy(s); return -1; } + /* Reuse the existing fd */ + s->fd = sock_fd; + wl_list_insert(display->socket_list.prev, &s->link); return 0; From ed680954c87a726a7e98c098b8c35604b1633295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 18 Jan 2016 18:18:16 +0800 Subject: [PATCH 0259/1152] protocol: Add note about per version requirements to wl_data_device_manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a note to the wl_data_device_manager global interface about the different requirements for operating the objects created from the bound global. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Carlos Garnacho <carlosg@gnome.org> --- protocol/wayland.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index b223bb4a..8739cd31 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -910,6 +910,11 @@ copy-and-paste and drag-and-drop. These mechanisms are tied to a wl_seat and this interface lets a client get a wl_data_device corresponding to a wl_seat. + + Depending on the version bound, the objects created from the bound + wl_data_device_manager object will have different requirements for + functioning properly. See wl_data_source.set_actions, + wl_data_offer.accept and wl_data_offer.finish for details. </description> <request name="create_data_source"> From 5ac34a101237a1534dcd7c14952f7c20ac2d9235 Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Wed, 27 Jan 2016 10:06:28 +0100 Subject: [PATCH 0260/1152] cosmetic: return NULL instead of 0 we're returning a pointer Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index e782309f..3f958779 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -127,7 +127,7 @@ wl_array_add(struct wl_array *array, size_t size) data = malloc(alloc); if (data == NULL) - return 0; + return NULL; array->data = data; array->alloc = alloc; } From 0d56e380f676e6fe475ffba71f11b480adf4e0a5 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 14 Jan 2016 13:33:52 -0600 Subject: [PATCH 0261/1152] server: Fail to bind object when requested version is 0 0 is not a valid version number for registry bind requests, so let's check for it in registry_bind. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-server.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 3ba8a5dd..ae9365f8 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -730,6 +730,11 @@ registry_bind(struct wl_client *client, wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid global %s (%d)", interface, name); + else if (version == 0) + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid version for global %s (%d): 0 is not a valid version", + interface, name); else if (global->version < version) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, From 7b42788f212079c2ef4c69c095efa50e90ca1301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 25 Jan 2016 17:28:06 +0800 Subject: [PATCH 0262/1152] scanner: Print filename on DTD validation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't just print prefix the errors with "protocol", but the actual file name, if wayland-scanner was passed with the filename of the protocol file. If wayland-scanner is reading from stdin, errors will be prefixed with "<stdin>" instead of "protocol". Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: David Fort <contact@hardening-consulting.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/scanner.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 1d626f41..dda54734 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -71,7 +71,7 @@ usage(int ret) } static bool -is_dtd_valid(FILE *input) +is_dtd_valid(FILE *input, const char *filename) { bool rc = true; #if HAVE_LIBXML @@ -101,7 +101,7 @@ is_dtd_valid(FILE *input) abort(); } - doc = xmlCtxtReadFd(ctx, fd, "protocol", NULL, 0); + doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0); if (!doc) { fprintf(stderr, "Failed to read XML\n"); abort(); @@ -1623,6 +1623,7 @@ int main(int argc, char *argv[]) struct parse_context ctx; struct protocol protocol; FILE *input = stdin; + char *input_filename = NULL; int len; void *buf; bool help = false, core_headers = false; @@ -1678,7 +1679,8 @@ int main(int argc, char *argv[]) usage(EXIT_FAILURE); if (argc == 3) { - input = fopen(argv[1], "r"); + input_filename = argv[1]; + input = fopen(input_filename, "r"); if (input == NULL) { fprintf(stderr, "Could not open input file: %s\n", strerror(errno)); @@ -1700,9 +1702,12 @@ int main(int argc, char *argv[]) /* initialize context */ memset(&ctx, 0, sizeof ctx); ctx.protocol = &protocol; - ctx.loc.filename = "<stdin>"; + if (input == stdin) + ctx.loc.filename = "<stdin>"; + else + ctx.loc.filename = input_filename; - if (!is_dtd_valid(input)) { + if (!is_dtd_valid(input, ctx.loc.filename)) { fprintf(stderr, "*******************************************************\n" "* *\n" From 816a0ae09bd5c370b95cee459905976dc14cfac0 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@bryceharrington.org> Date: Tue, 2 Feb 2016 15:30:36 -0800 Subject: [PATCH 0263/1152] configure.ac: bump to version 1.9.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2469cdb3..63dd2cfe 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [9]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 369b6466a71175289572c4ef8f70af65f620fb88 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Tue, 2 Feb 2016 14:56:57 -0600 Subject: [PATCH 0264/1152] scanner: Fix oddities in copyright printing Some copyright strings could result in broken generated header files with unmatched */ This change: Runs the loop long enough so the copyright[i] == 0 test can actually happen. (if there was no \n no copyright text was printed, */ still was) Prints the opening /* even if there was whitespace at the start of the very first line. Only emits a */ if a /* was printed. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Jon A. Cruz <jonc@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/scanner.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index dda54734..d3e2328f 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1284,25 +1284,29 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid static void format_copyright(const char *copyright) { - int bol = 1, start = 0, i; + int bol = 1, start = 0, i, length; + bool comment_started = false; - for (i = 0; copyright[i]; i++) { + length = strlen(copyright); + for (i = 0; i <= length; i++) { if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) { continue; } else if (bol) { bol = 0; start = i; } - - if (copyright[i] == '\n' || copyright[i] == '\0') { + if (copyright[i] == '\n' || + (copyright[i] == '\0' && !(start == i))) { printf("%s%s%.*s\n", - i == 0 ? "/*" : " *", + comment_started ? " *" : "/*", i > start ? " " : "", i - start, copyright + start); bol = 1; + comment_started = true; } } - printf(" */\n\n"); + if (comment_started) + printf(" */\n\n"); } static void From 6301639146474795da10952db86ea3ef4849f568 Mon Sep 17 00:00:00 2001 From: Sergi Granell <xerpi.g.12@gmail.com> Date: Thu, 4 Feb 2016 21:35:07 +0100 Subject: [PATCH 0265/1152] cosmetic: use tabs instead of spaces --- src/wayland-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 3f958779..748476a2 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -123,7 +123,7 @@ wl_array_add(struct wl_array *array, size_t size) if (array->alloc < alloc) { if (array->alloc > 0) data = realloc(array->data, alloc); - else + else data = malloc(alloc); if (data == NULL) From d33514379d311bd9ddd4a2e1e97c8205a8111d3c Mon Sep 17 00:00:00 2001 From: Sergi Granell <xerpi.g.12@gmail.com> Date: Thu, 4 Feb 2016 21:48:21 +0100 Subject: [PATCH 0266/1152] cosmetic: add an space after if --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 8e7adc92..a4343a4e 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -117,7 +117,7 @@ format_is_supported(struct wl_client *client, uint32_t format) default: formats = wl_display_get_additional_shm_formats(display); wl_array_for_each(p, formats) - if(*p == format) + if (*p == format) return true; } From 1906a90aab613501396fe4fb72c7fba9e13ee161 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 9 Feb 2016 13:26:21 -0800 Subject: [PATCH 0267/1152] configure.ac: bump to version 1.9.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 63dd2cfe..ba7e4453 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [9]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From bf34ac75d0d61609296de1300196c843f4246e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Wed, 10 Feb 2016 23:35:44 +0800 Subject: [PATCH 0268/1152] connection: Don't add uninitialized memory as 4 byte alignment padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we are adding padding bytes making our wl_buffer buffer content 4 byte aligned, we are just moving the pointer. Since the buffer is allocated using plain malloc(), this means our padding bytes are effectively uninitialized data, which could be anything previously allocated in the server process. As we'll be sharing this buffer content with arbitrary clients, we are effectively sharing private memory with every client, and even though a well behaving client will discard any such memory, a malicious client may not. Therefor, to avoid any potential missuse of the uninitialized padding memory shared between the server and client, initialize the buffer content to 0, making the padding bytes always 0. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index 65b64e9d..c0e322fb 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1137,7 +1137,7 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) return -1; buffer_size = buffer_size_for_closure(closure); - buffer = malloc(buffer_size * sizeof buffer[0]); + buffer = zalloc(buffer_size * sizeof buffer[0]); if (buffer == NULL) return -1; From 0ff73b7666b8aee1a68302dd6a7664b68aa659af Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 16 Feb 2016 12:03:40 -0800 Subject: [PATCH 0269/1152] configure.ac: bump to version 1.10.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index ba7e4453..f54a8b95 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [9]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [10]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 22acc9cec921720bacfdf77e13a73fdb4a379876 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 16 Feb 2016 17:15:26 -0800 Subject: [PATCH 0270/1152] configure.ac: bump to version 1.10.90 for open development Master is open for new feature development again. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f54a8b95..65ab8efb 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [10]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 6801d2d851ff5494c992d6b354964032da7647d6 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 14 Jan 2016 14:32:38 -0600 Subject: [PATCH 0271/1152] resource-test: Use wl_seat instead of wl_display for testing We're creating resources with versions up to 4. wl_display isn't version 4, so this is technically verifying that we can do something we shouldn't. wl_seat already has versions this high, so switch to that. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- tests/resources-test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/resources-test.c b/tests/resources-test.c index ea88afbb..337f9f9f 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -45,7 +45,7 @@ TEST(create_resource_tst) client = wl_client_create(display, s[0]); assert(client); - res = wl_resource_create(client, &wl_display_interface, 4, 0); + res = wl_resource_create(client, &wl_seat_interface, 4, 0); assert(res); /* setters/getters */ @@ -105,7 +105,7 @@ TEST(destroy_res_tst) client = wl_client_create(display, s[0]); assert(client); - res = wl_resource_create(client, &wl_display_interface, 4, 0); + res = wl_resource_create(client, &wl_seat_interface, 4, 0); assert(res); wl_resource_set_implementation(res, NULL, &destroyed, res_destroy_func); wl_resource_add_destroy_listener(res, &destroy_listener); @@ -119,7 +119,7 @@ TEST(destroy_res_tst) assert(notify_called); /* check if signal was emitted */ assert(wl_client_get_object(client, id) == NULL); - res = wl_resource_create(client, &wl_display_interface, 2, 0); + res = wl_resource_create(client, &wl_seat_interface, 2, 0); assert(res); destroyed = 0; notify_called = 0; @@ -149,13 +149,13 @@ TEST(create_resource_with_same_id) client = wl_client_create(display, s[0]); assert(client); - res = wl_resource_create(client, &wl_display_interface, 2, 0); + res = wl_resource_create(client, &wl_seat_interface, 2, 0); assert(res); id = wl_resource_get_id(res); assert(wl_client_get_object(client, id) == res); /* this one should replace the old one */ - res2 = wl_resource_create(client, &wl_display_interface, 1, id); + res2 = wl_resource_create(client, &wl_seat_interface, 1, id); assert(res2 != NULL); assert(wl_client_get_object(client, id) == res2); From 88ff135ad46b556b6fdeb1244ffd019a262967bc Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Fri, 15 Jan 2016 10:06:48 -0600 Subject: [PATCH 0272/1152] server: validate resource versions at creation time We shouldn't ever create a resource with version less than 1 or greater than the interface version. Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Signed-off-by: Derek Foreman <derekf@osg.samsung.com> --- src/wayland-server.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index ae9365f8..67cdd0c9 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1390,6 +1390,13 @@ wl_resource_create(struct wl_client *client, { struct wl_resource *resource; + if (version < 1 || version > interface->version) { + wl_log("wl_resource_create: invalid resource version %d " + "for interface '%s' - must be in range [1, %d]\n", + version, interface->name, interface->version); + return NULL; + } + resource = malloc(sizeof *resource); if (resource == NULL) return NULL; From 8216abc5877a29bd8c20d8adb257e084d1390f29 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Fri, 15 Jan 2016 13:33:52 -0600 Subject: [PATCH 0273/1152] build: Add an --enable-fatal-warnings configure option New --enable-fatal-warnings ./configure option that just adds -Werror to GCC_CFLAGS Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- configure.ac | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 65ab8efb..af5b7cd2 100644 --- a/configure.ac +++ b/configure.ac @@ -47,8 +47,17 @@ LT_INIT PKG_PROG_PKG_CONFIG() +AC_ARG_ENABLE([fatal-warnings], + AC_HELP_STRING([--enable-fatal-warnings], + [Build with -Werror]), + [enable_fatal_warnings=$enableval], + [enable_fatal_warnings=no]) +AS_IF([test x"$enable_fatal_warnings" != "xno"], [ + WERROR_CFLAGS="-Werror" +]) + if test "x$GCC" = "xyes"; then - GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden" + GCC_CFLAGS="$WERROR_CFLAGS -Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden" fi AC_SUBST(GCC_CFLAGS) From 8125919b0d8e7c776652e4f1d829b9edfa6c4a68 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Fri, 15 Jan 2016 13:33:53 -0600 Subject: [PATCH 0274/1152] build: build distcheck with --enable-fatal-warnings Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index e850abce..5e5576e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,6 +11,8 @@ AM_CPPFLAGS = \ AM_CFLAGS = $(GCC_CFLAGS) +AM_DISTCHECK_CONFIGURE_FLAGS = --enable-fatal-warnings + aclocaldir = $(datadir)/aclocal dist_aclocal_DATA = wayland-scanner.m4 From 8f2da5e82b45bc69db2a575aa9832027d010c307 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Wed, 17 Feb 2016 09:12:58 -0600 Subject: [PATCH 0275/1152] Revert "build: build distcheck with --enable-fatal-warnings" This reverts commit 8125919b0d8e7c776652e4f1d829b9edfa6c4a68. This makes things far more annoying than intended, especially since the list of default warnings isn't consistent from distro to distro. --- Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 5e5576e9..e850abce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,8 +11,6 @@ AM_CPPFLAGS = \ AM_CFLAGS = $(GCC_CFLAGS) -AM_DISTCHECK_CONFIGURE_FLAGS = --enable-fatal-warnings - aclocaldir = $(datadir)/aclocal dist_aclocal_DATA = wayland-scanner.m4 From 3a2553ff013a3661ec044917ccde4a74fe152dc9 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Thu, 18 Feb 2016 18:23:05 -0600 Subject: [PATCH 0276/1152] Revert "server: validate resource versions at creation time" This reverts commit 88ff135ad46b556b6fdeb1244ffd019a262967bc. The parent interface version may be higher than this interface version, and the child object should inherit that version. This check is wrong. --- src/wayland-server.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 67cdd0c9..ae9365f8 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1390,13 +1390,6 @@ wl_resource_create(struct wl_client *client, { struct wl_resource *resource; - if (version < 1 || version > interface->version) { - wl_log("wl_resource_create: invalid resource version %d " - "for interface '%s' - must be in range [1, %d]\n", - version, interface->name, interface->version); - return NULL; - } - resource = malloc(sizeof *resource); if (resource == NULL) return NULL; From cde251a124d41977b447098cc530fcad2834a45f Mon Sep 17 00:00:00 2001 From: Bill Spitzak <spitzak@gmail.com> Date: Fri, 6 Nov 2015 08:27:27 -0800 Subject: [PATCH 0277/1152] doc: Use enum argument type to make links in protocol documentation Reviewed-by: Auke Booij <auke@tulcod.com> --- doc/publican/protocol-to-docbook.xsl | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index fad207a8..5344442d 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -102,12 +102,6 @@ <term><xsl:value-of select="@name"/></term> <listitem> <simpara> - <xsl:if test="@enum"> - <link linkend="protocol-spec-{../../@name}-enum-{@enum}"> - <xsl:value-of select="@enum"/> - </link> - <xsl:text> </xsl:text> - </xsl:if> <xsl:value-of select="@type"/> <xsl:if test="@summary" > - <xsl:value-of select="@summary"/> @@ -152,6 +146,24 @@ </varlistentry> </xsl:template> +<!-- enum and bitfield arguemnts --> +<xsl:template match="arg[@enum]"> + <varlistentry> + <term><xsl:value-of select="@name"/></term> + <listitem> + <simpara> + <link linkend="protocol-spec-{../../@name}-enum-{@enum}"> + <xsl:value-of select="../../@name"/>::<xsl:value-of select="@enum"/> + </link> + (<xsl:value-of select="@type"/>) + <xsl:if test="@summary" > + - <xsl:value-of select="@summary"/> + </xsl:if> + </simpara> + </listitem> + </varlistentry> +</xsl:template> + <!-- Request/event list --> <xsl:template match="request|event"> <section id="protocol-spec-{../@name}-{name()}-{@name}"> @@ -174,7 +186,7 @@ <!-- Enumeration --> <xsl:template match="enum"> - <section id="protocol-spec-{../@name}-{name()}-{@name}"> + <section id="protocol-spec-{../@name}-enum-{@name}"> <title> <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> <xsl:if test="@bitfield"> From 25fcb88a269a434196cf89df835ba6326bacacab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Mon, 22 Feb 2016 13:37:26 +0800 Subject: [PATCH 0278/1152] client: Don't segfault when receiving error on destroyed object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an error is received on a destroyed object, we'd get NULL passed to display_handle_error() instead of a pointer to a valid wl_proxy. The logging is changed to report [unknown interface] and [unknown id] instead of the actual interface name and id. The wl_display_get_protocol_error() documentation is updated to handle the situation. For when the proxy was NULL, the object id 0 and interface NULL is written. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> [Pekka: changed the error message wording] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Jonas Ådahl <jadahl@gmail.com> --- src/wayland-client.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index ef12bfcc..297c7a5f 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -177,7 +177,7 @@ display_protocol_error(struct wl_display *display, uint32_t code, return; /* set correct errno */ - if (wl_interface_equal(intf, &wl_display_interface)) { + if (intf && wl_interface_equal(intf, &wl_display_interface)) { switch (code) { case WL_DISPLAY_ERROR_INVALID_OBJECT: case WL_DISPLAY_ERROR_INVALID_METHOD: @@ -790,12 +790,26 @@ display_handle_error(void *data, uint32_t code, const char *message) { struct wl_proxy *proxy = object; + uint32_t object_id; + const struct wl_interface *interface; - wl_log("%s@%u: error %d: %s\n", - proxy->object.interface->name, proxy->object.id, code, message); + if (proxy) { + wl_log("%s@%u: error %d: %s\n", + proxy->object.interface->name, + proxy->object.id, + code, message); - display_protocol_error(display, code, proxy->object.id, - proxy->object.interface); + object_id = proxy->object.id; + interface = proxy->object.interface; + } else { + wl_log("[destroyed object]: error %d: %s\n", + code, message); + + object_id = 0; + interface = NULL; + } + + display_protocol_error(display, code, object_id, interface); } static void @@ -1756,10 +1770,12 @@ wl_display_get_error(struct wl_display *display) /** Retrieves the information about a protocol error: * * \param display The Wayland display - * \param interface if not NULL, stores the interface where the error occurred + * \param interface if not NULL, stores the interface where the error occurred, + * or NULL, if unknown. * \param id if not NULL, stores the object id that generated - * the error. There's no guarantee the object is - * still valid; the client must know if it deleted the object. + * the error, or 0, if the object id is unknown. There's no + * guarantee the object is still valid; the client must know + * if it deleted the object. * \return The error code as defined in the interface specification. * * \code From 564623653a146ba74714bcf3569d8082a2afd3f0 Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Mon, 22 Feb 2016 14:37:00 +0100 Subject: [PATCH 0279/1152] tests: add test for receiving an error on destroyed object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test if receiving an error on already destroyed object won't do any harm Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> Tested-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- tests/display-test.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index 1a6c3456..f9f81600 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -876,3 +876,53 @@ TEST(versions) display_destroy(d); } + +static void +check_error_on_destroyed_object(void *data) +{ + struct client *c; + struct wl_seat *seat; + uint32_t id; + const struct wl_interface *intf; + + c = client_connect(); + seat = client_get_seat(c); + + /* destroy the seat proxy. The display won't know + * about it yet, so it will post the error as usual */ + wl_proxy_destroy((struct wl_proxy *) seat); + + /* let display post the error. The error will + * be caught in stop_display while dispatching */ + assert(stop_display(c, 1) == -1); + + /* check the returned error. Since the object was destroyed, + * we don't know the interface and id */ + assert(wl_display_get_error(c->wl_display) == EPROTO); + assert(wl_display_get_protocol_error(c->wl_display, &intf, &id) == 23); + assert(intf == NULL); + assert(id == 0); + + client_disconnect_nocheck(c); +} + +TEST(error_on_destroyed_object) +{ + struct client_info *cl; + struct display *d = display_create(); + + wl_global_create(d->wl_display, &wl_seat_interface, + 1, d, bind_seat); + + cl = client_create_noarg(d, check_error_on_destroyed_object); + display_run(d); + + /* did client bind to the seat? */ + assert(cl->data); + + /* post error on the destroyed object */ + wl_resource_post_error((struct wl_resource *) cl->data, + 23, "Dummy error"); + display_resume(d); + display_destroy(d); +} From 4a41d26c4d0f4775f3a013a41a32ac1512a0a177 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Date: Mon, 29 Feb 2016 14:59:51 +0200 Subject: [PATCH 0280/1152] build: fix ./configure --disable-dtd-validation When configured with --disable-dtd-validation: CPPAS src/dtddata.o src/dtddata.S: Assembler messages: src/dtddata.S:39: Error: file not found: src/wayland.dtd.embed Makefile:1520: recipe for target 'src/dtddata.o' failed This is because the variable name used does not match the implicit variable name in autoconf. Fix the variable name, making both --disable-dtd-validation and --enable-dtd-validation to what they should. Do not try to build dtddata.S if dtd-validation is disabled. It depends on wayland.dtd.embed which is created by configure only if dtd-validation is enabled. If not building dtddata.S, also make sure the extern definitions in scanner.c are compiled out. Bugzilla: https://bugs.gentoo.org/show_bug.cgi?id=575212 Reported-by: leio@gentoo.org Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Tested-by: Bryce Harrington <bryce@osg.samsung.com> --- Makefile.am | 5 ++++- configure.ac | 5 +++-- src/scanner.c | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index e850abce..49e25a66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,11 +23,14 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = bin_PROGRAMS = wayland-scanner -wayland_scanner_SOURCES = src/scanner.c src/dtddata.S +wayland_scanner_SOURCES = src/scanner.c wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(LIBXML_CFLAGS) $(AM_CFLAGS) wayland_scanner_LDADD = $(EXPAT_LIBS) $(LIBXML_LIBS) libwayland-util.la pkgconfig_DATA += src/wayland-scanner.pc +if DTD_VALIDATION +wayland_scanner_SOURCES += src/dtddata.S +endif src/dtddata.o: protocol/wayland.dtd if USE_HOST_SCANNER diff --git a/configure.ac b/configure.ac index af5b7cd2..bbe62f7d 100644 --- a/configure.ac +++ b/configure.ac @@ -85,7 +85,7 @@ AC_ARG_ENABLE([dtd-validation], [AC_HELP_STRING([--disable-dtd-validation], [Disable DTD validation of the protocol])], [], - [enable_dtdvalidation=yes]) + [enable_dtd_validation=yes]) AM_CONDITIONAL(USE_HOST_SCANNER, test "x$with_host_scanner" = xyes) @@ -121,7 +121,8 @@ PKG_CHECK_MODULES(EXPAT, [expat], [], AC_SUBST(EXPAT_LIBS) ]) -if test "x$enable_dtdvalidation" = "xyes"; then +AM_CONDITIONAL([DTD_VALIDATION], [test "x$enable_dtd_validation" = "xyes"]) +if test "x$enable_dtd_validation" = "xyes"; then PKG_CHECK_MODULES(LIBXML, [libxml-2.0]) AC_DEFINE(HAVE_LIBXML, 1, [libxml-2.0 is available]) AC_CONFIG_LINKS([src/wayland.dtd.embed:protocol/wayland.dtd]) diff --git a/src/scanner.c b/src/scanner.c index d3e2328f..04747e39 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -40,13 +40,13 @@ #if HAVE_LIBXML #include <libxml/parser.h> -#endif - -#include "wayland-util.h" /* Embedded wayland.dtd file, see dtddata.S */ extern char DTD_DATA_begin; extern int DTD_DATA_len; +#endif + +#include "wayland-util.h" enum side { CLIENT, From f8f3e54aa7bc15871ca4296cbc16ae065b07de4e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Date: Wed, 2 Mar 2016 11:00:35 +0200 Subject: [PATCH 0281/1152] scanner: avoid executable stack Before this patch: $ scanelf -lpqe ./wayland-scanner RWX --- --- ./wayland-scanner That indicates the stack is executable, which is a bad thing for security. Wayland-scanner does not actually need an executable stack, it is just an oversight from using an .S file in the sources. Add a special incantation in dtddata.S to make it not cause the stack to become executable. Reported-by: Mart Raudsepp <leio@gentoo.org> Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Mart Raudsepp <leio@gentoo.org> --- src/dtddata.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dtddata.S b/src/dtddata.S index 68e3435a..ce51133c 100644 --- a/src/dtddata.S +++ b/src/dtddata.S @@ -20,6 +20,14 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* + * Avoid executable stack. + * from: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart + */ +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + /* from: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967#comment-348129 */ .macro binfile name file From 2b5310a367a81a6132207c398d188edc9e34c15f Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Tue, 1 Mar 2016 09:26:21 +1000 Subject: [PATCH 0282/1152] doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/doxygen/Makefile.am | 27 +++- doc/doxygen/mainpage.dox | 13 ++ doc/doxygen/wayland.doxygen.in | 6 + src/scanner.c | 220 +++++++++++++++++++++------------ 4 files changed, 188 insertions(+), 78 deletions(-) create mode 100644 doc/doxygen/mainpage.dox diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index a8bb95f8..e80c401a 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -1,7 +1,11 @@ .SUFFIXES = .gv .png .map -noinst_DATA = xml/Client/index.xml xml/Server/index.xml +noinst_DATA = \ + xml/Client/index.xml \ + xml/Server/index.xml \ + html/Client/index.html \ + html/Server/index.html dist_noinst_DATA = wayland.doxygen.in scanned_src_files_shared = \ @@ -27,6 +31,17 @@ scanned_src_files_man = \ $(top_srcdir)/src/wayland-client.h \ $(top_srcdir)/src/wayland-client-core.h +extra_doxygen = \ + mainpage.dox + +extra_doxygen_Server = \ + $(top_builddir)/protocol/wayland-server-protocol.h \ + $(extra_doxygen) + +extra_doxygen_Client = \ + $(top_builddir)/protocol/wayland-client-protocol.h \ + $(extra_doxygen) + diagramsdir := $(srcdir)/dot diagramssrc := $(wildcard $(diagramsdir)/*.gv) diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png)) @@ -38,7 +53,7 @@ diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map)) dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") # Listing various directories that might need to be created. -alldirs := xml xml/Client xml/Server man/man3 +alldirs := xml xml/Client xml/Server man/man3 html/Client html/Server $(diagrams): $(diagramssrc) @@ -51,6 +66,13 @@ xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxy echo "INPUT= $(scanned_src_files_$*)"; \ ) | $(DOXYGEN) - +html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | html/% + $(AM_V_GEN)(cat wayland.doxygen; \ + echo "GENERATE_HTML=YES"; \ + echo "HTML_OUTPUT=html/$*"; \ + echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \ + ) | $(DOXYGEN) - + man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | man/man3 $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_MAN=YES"; \ @@ -74,6 +96,7 @@ all-local: man/man3/wl_display.3 clean-local: rm -rf xml/ + rm -rf html/ rm -rf man/ EXTRA_DIST = $(diagramssrc) diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox new file mode 100644 index 00000000..8f9bf030 --- /dev/null +++ b/doc/doxygen/mainpage.dox @@ -0,0 +1,13 @@ +/** + * @mainpage + * Wayland protocol API documentation. + * + * @section ifaces Interfaces + * For the list of available interfaces, please see the + * <a href="modules.html">modules</a> list. + * + * @section protocols Protocols + * For the list of protocols, please see the + * <a href="pages.html">Related Pages</a>. + * + */ diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in index fb76b123..9d7fa0c4 100644 --- a/doc/doxygen/wayland.doxygen.in +++ b/doc/doxygen/wayland.doxygen.in @@ -13,4 +13,10 @@ MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES DOT_MULTI_TARGETS = YES ALIASES += comment{1}="/* \1 *<!-- -->/" +OPTIMIZE_OUTPUT_FOR_C = YES +EXTRACT_ALL = YES +EXTRACT_STATIC = YES +# These must be set in the Makefile GENERATE_HTML = NO +GENERATE_XML = NO +GENERATE_MAN = NO diff --git a/src/scanner.c b/src/scanner.c index 04747e39..a895f92a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -876,6 +876,34 @@ character_data(void *data, const XML_Char *s, int len) ctx->character_data_length += len; } +static void +format_text_to_comment(const char *text, bool standalone_comment) +{ + int bol = 1, start = 0, i, length; + bool comment_started = !standalone_comment; + + length = strlen(text); + for (i = 0; i <= length; i++) { + if (bol && (text[i] == ' ' || text[i] == '\t')) { + continue; + } else if (bol) { + bol = 0; + start = i; + } + if (text[i] == '\n' || + (text[i] == '\0' && !(start == i))) { + printf("%s%s%.*s\n", + comment_started ? " *" : "/*", + i > start ? " " : "", + i - start, text + start); + bol = 1; + comment_started = true; + } + } + if (comment_started && standalone_comment) + printf(" */\n\n"); +} + static void emit_opcodes(struct wl_list *message_list, struct interface *interface) { @@ -898,9 +926,11 @@ emit_opcode_versions(struct wl_list *message_list, struct interface *interface) { struct message *m; - wl_list_for_each(m, message_list, link) + wl_list_for_each(m, message_list, link) { + printf("/**\n * @ingroup iface_%s\n */\n", interface->name); printf("#define %s_%s_SINCE_VERSION\t%d\n", interface->uppercase_name, m->uppercase_name, m->since); + } printf("\n"); } @@ -940,6 +970,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) struct arg *a, *ret; int has_destructor, has_destroy; + printf("/** @ingroup iface_%s */\n", interface->name); printf("static inline void\n" "%s_set_user_data(struct %s *%s, void *user_data)\n" "{\n" @@ -948,6 +979,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) interface->name, interface->name, interface->name, interface->name); + printf("/** @ingroup iface_%s */\n", interface->name); printf("static inline void *\n" "%s_get_user_data(struct %s *%s)\n" "{\n" @@ -981,7 +1013,8 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) exit(EXIT_FAILURE); } - if (!has_destroy && strcmp(interface->name, "wl_display") != 0) + if (!has_destroy && strcmp(interface->name, "wl_display") != 0) { + printf("/** @ingroup iface_%s */\n", interface->name); printf("static inline void\n" "%s_destroy(struct %s *%s)\n" "{\n" @@ -990,6 +1023,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) "}\n\n", interface->name, interface->name, interface->name, interface->name); + } if (wl_list_empty(message_list)) return; @@ -1009,6 +1043,11 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) ret = a; } + printf("/**\n" + " * @ingroup iface_%s\n", interface->name); + if (m->description && m->description->text) + format_text_to_comment(m->description->text, false); + printf(" */\n"); if (ret && ret->interface_name == NULL) printf("static inline void *\n"); else if (ret) @@ -1104,6 +1143,17 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface) return; wl_list_for_each(m, message_list, link) { + printf("/**\n" + " * @ingroup iface_%s\n" + " * Sends an %s event to the client owning the resource.\n", + interface->name, + m->name); + printf("* @param resource_ The client's resource\n"); + wl_list_for_each(a, &m->arg_list, link) { + if (a->summary) + printf(" * @param %s %s\n", a->name, a->summary); + } + printf(" */\n"); printf("static inline void\n" "%s_send_%s(struct wl_resource *resource_", interface->name, m->name); @@ -1150,28 +1200,23 @@ emit_enumerations(struct interface *interface) if (desc) { printf("/**\n"); - desc_dump(desc->summary, - " * %s_%s - ", - interface->name, e->name); - wl_list_for_each(entry, &e->entry_list, link) { - desc_dump(entry->summary, - " * @%s_%s_%s: ", - interface->uppercase_name, - e->uppercase_name, - entry->uppercase_name); - } - if (desc->text) { - printf(" *\n"); - desc_dump(desc->text, " * "); - } + printf(" * @ingroup iface_%s\n", interface->name); + format_text_to_comment(desc->summary, false); + if (desc->text) + format_text_to_comment(desc->text, false); printf(" */\n"); } printf("enum %s_%s {\n", interface->name, e->name); - wl_list_for_each(entry, &e->entry_list, link) + wl_list_for_each(entry, &e->entry_list, link) { + if (entry->summary) + printf("\t/**\n" + "\t * %s\n" + "\t */\n", entry->summary); printf("\t%s_%s_%s = %s,\n", interface->uppercase_name, e->uppercase_name, entry->uppercase_name, entry->value); + } printf("};\n"); printf("#endif /* %s_%s_ENUM */\n\n", interface->uppercase_name, e->uppercase_name); @@ -1188,20 +1233,11 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid if (wl_list_empty(message_list)) return; - if (interface->description) { - struct description *desc = interface->description; - printf("/**\n"); - desc_dump(desc->summary, " * %s - ", interface->name); - wl_list_for_each(m, message_list, link) { - struct description *mdesc = m->description; - desc_dump(mdesc ? mdesc->summary : "(none)", - " * @%s: ", - m->name); - } - printf(" *\n"); - desc_dump(desc->text, " * "); - printf(" */\n"); - } + printf("/**\n"); + printf(" * @ingroup iface_%s\n", interface->name); + printf(" * @struct %s_%s\n", interface->name, + (side == SERVER) ? "interface" : "listener"); + printf(" */\n"); printf("struct %s_%s {\n", interface->name, (side == SERVER) ? "interface" : "listener"); @@ -1209,24 +1245,24 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid struct description *mdesc = m->description; printf("\t/**\n"); - desc_dump(mdesc ? mdesc->summary : "(none)", - "\t * %s - ", m->name); - wl_list_for_each(a, &m->arg_list, link) { - if (side == SERVER && a->type == NEW_ID && - a->interface_name == NULL) - printf("\t * @interface: name of the objects interface\n" - "\t * @version: version of the objects interface\n"); - - - desc_dump(a->summary ? a->summary : "(none)", - "\t * @%s: ", a->name); - } if (mdesc) { + if (mdesc->summary) + printf("\t * %s\n", mdesc->summary); printf("\t *\n"); desc_dump(mdesc->text, "\t * "); } + wl_list_for_each(a, &m->arg_list, link) { + if (side == SERVER && a->type == NEW_ID && + a->interface_name == NULL) + printf("\t * @param interface name of the objects interface\n" + "\t * @param version version of the objects interface\n"); + + if (a->summary) + printf("\t * @param %s %s\n", a->name, + a->summary); + } if (m->since > 1) { - printf("\t * @since: %d\n", m->since); + printf("\t * @since %d\n", m->since); } printf("\t */\n"); printf("\tvoid (*%s)(", m->name); @@ -1266,6 +1302,9 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid printf("};\n\n"); if (side == CLIENT) { + printf("/**\n" + " * @ingroup %s_iface\n" + " */\n", interface->name); printf("static inline int\n" "%s_add_listener(struct %s *%s,\n" "%sconst struct %s_listener *listener, void *data)\n" @@ -1281,34 +1320,6 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid } } -static void -format_copyright(const char *copyright) -{ - int bol = 1, start = 0, i, length; - bool comment_started = false; - - length = strlen(copyright); - for (i = 0; i <= length; i++) { - if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) { - continue; - } else if (bol) { - bol = 0; - start = i; - } - if (copyright[i] == '\n' || - (copyright[i] == '\0' && !(start == i))) { - printf("%s%s%.*s\n", - comment_started ? " *" : "/*", - i > start ? " " : "", - i - start, copyright + start); - bol = 1; - comment_started = true; - } - } - if (comment_started) - printf(" */\n\n"); -} - static void emit_types_forward_declarations(struct protocol *protocol, struct wl_list *message_list, @@ -1361,6 +1372,46 @@ get_include_name(bool core, enum side side) return core ? "wayland-client-core.h" : "wayland-client.h"; } +static void +emit_mainpage_blurb(const struct protocol *protocol, enum side side) +{ + struct interface *i; + + printf("/**\n" + " * @page page_%s The %s protocol\n", + protocol->name, protocol->name); + + if (protocol->description) { + if (protocol->description->summary) { + printf(" * %s\n" + " *\n", protocol->description->summary); + } + + if (protocol->description->text) { + printf(" * @section page_desc_%s Description\n", protocol->name); + format_text_to_comment(protocol->description->text, false); + printf(" *\n"); + } + } + + printf(" * @section page_ifaces_%s Interfaces\n", protocol->name); + wl_list_for_each(i, &protocol->interface_list, link) { + printf(" * - @subpage page_iface_%s - %s\n", + i->name, + i->description && i->description->summary ? i->description->summary : ""); + } + + if (protocol->copyright) { + printf(" * @section page_copyright_%s Copyright\n", + protocol->name); + printf(" * <pre>\n"); + format_text_to_comment(protocol->copyright, false); + printf(" * </pre>\n"); + } + + printf(" */\n"); +} + static void emit_header(struct protocol *protocol, enum side side) { @@ -1369,9 +1420,6 @@ emit_header(struct protocol *protocol, enum side side) const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; char **p, *prev; - if (protocol->copyright) - format_copyright(protocol->copyright); - printf("#ifndef %s_%s_PROTOCOL_H\n" "#define %s_%s_PROTOCOL_H\n" "\n" @@ -1388,6 +1436,8 @@ emit_header(struct protocol *protocol, enum side side) protocol->uppercase_name, s, get_include_name(protocol->core_headers, side)); + emit_mainpage_blurb(protocol, side); + wl_array_init(&types); wl_list_for_each(i, &protocol->interface_list, link) { emit_types_forward_declarations(protocol, &i->request_list, &types); @@ -1411,6 +1461,24 @@ emit_header(struct protocol *protocol, enum side side) printf("\n"); wl_list_for_each(i, &protocol->interface_list, link) { + printf("/**\n" + " * @page page_iface_%s %s\n", + i->name, i->name); + if (i->description && i->description->text) { + printf(" * @section page_iface_%s_desc Description\n", + i->name); + format_text_to_comment(i->description->text, false); + } + printf(" * @section page_iface_%s_api API\n" + " * See @ref iface_%s.\n" + " */\n", + i->name, i->name); + printf("/**\n" + " * @defgroup iface_%s The %s interface\n", + i->name, i->name); + if (i->description && i->description->text) + format_text_to_comment(i->description->text, false); + printf(" */\n"); printf("extern const struct wl_interface " "%s_interface;\n", i->name); } @@ -1554,7 +1622,7 @@ emit_code(struct protocol *protocol) char **p, *prev; if (protocol->copyright) - format_copyright(protocol->copyright); + format_text_to_comment(protocol->copyright, true); printf("#include <stdlib.h>\n" "#include <stdint.h>\n" From 973a70dbb5a1d2865ec63a268e939585da5a951f Mon Sep 17 00:00:00 2001 From: Peter Hutterer <peter.hutterer@who-t.net> Date: Tue, 1 Mar 2016 09:28:49 +1000 Subject: [PATCH 0283/1152] doc: link between client and server doc and to the wayland book And insert "client" or "server" into the PROJECT_NAME to know which one we have. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/doxygen/Makefile.am | 1 + doc/doxygen/mainpage.dox | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index e80c401a..c3773536 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -68,6 +68,7 @@ xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxy html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | html/% $(AM_V_GEN)(cat wayland.doxygen; \ + echo "PROJECT_NAME=\"Wayland $* API\""; \ echo "GENERATE_HTML=YES"; \ echo "HTML_OUTPUT=html/$*"; \ echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \ diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox index 8f9bf030..ca1da53c 100644 --- a/doc/doxygen/mainpage.dox +++ b/doc/doxygen/mainpage.dox @@ -2,6 +2,15 @@ * @mainpage * Wayland protocol API documentation. * + * This documentation is available for the Server- and the Client-side APIs. + * + * - <a href="../Server/index.html">Server-side API</a> + * - <a href="../Client/index.html">Client-side API</a> + * + * Further documentation about the architecture and principles of Wayland is + * available in the + * <a href="https://wayland.freedesktop.org/docs/html">Wayland Book</a> + * * @section ifaces Interfaces * For the list of available interfaces, please see the * <a href="modules.html">modules</a> list. From ba2ee84113e7f9fef9af2ec3998ee437adab5382 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Fri, 4 Mar 2016 10:50:23 -0800 Subject: [PATCH 0284/1152] doc: Note strong recommendation to use S-o-b in contributions Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- doc/Contributing | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/Contributing b/doc/Contributing index fe906141..65565dca 100644 --- a/doc/Contributing +++ b/doc/Contributing @@ -30,6 +30,15 @@ cope with the way git log presents them. See [2] for a recommend reading on writing commit messages. +Your patches should also include a Signed-off-by line with your name and +email address. If you're not the patch's original author, you should +also gather S-o-b's by them (and/or whomever gave the patch to you.) The +significance of this is that it certifies that you created the patch, +that it was created under an appropriate open source license, or +provided to you under those terms. This lets us indicate a chain of +responsibility for the copyright status of the code. + +We won't reject patches that lack S-o-b, but it is strongly recommended. == Tracking patches and following up == From 5fe7e7ca78eb8c5435f35ed47b54aabdbdcaadf7 Mon Sep 17 00:00:00 2001 From: Sergi Granell <xerpi.g.12@gmail.com> Date: Thu, 18 Feb 2016 23:59:29 +0100 Subject: [PATCH 0285/1152] server: Fix shm_create_pool size fail path fd leak If the client passed a size <= 0 to shm_create_pool, it would go to err_free, which wouldn't close the fd, and thus leave it opened. We can also move the size check before the struct wl_shm_pool malloc, so in case the client passes a wrong size, it won't do an unnecessary malloc and then free. Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-shm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index a4343a4e..81bf6571 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -230,17 +230,17 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, { struct wl_shm_pool *pool; - pool = malloc(sizeof *pool); - if (pool == NULL) { - wl_client_post_no_memory(client); - goto err_close; - } - if (size <= 0) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE, "invalid size (%d)", size); - goto err_free; + goto err_close; + } + + pool = malloc(sizeof *pool); + if (pool == NULL) { + wl_client_post_no_memory(client); + goto err_close; } pool->refcount = 1; @@ -251,7 +251,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, "failed mmap fd %d", fd); - goto err_close; + goto err_free; } close(fd); @@ -270,10 +270,10 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, return; -err_close: - close(fd); err_free: free(pool); +err_close: + close(fd); } static const struct wl_shm_interface shm_interface = { From 442f4435868c1ea37e99d3f4fb316434e96faab1 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Tue, 9 Feb 2016 16:03:47 -0600 Subject: [PATCH 0286/1152] shm: Split pool reference counting into external and internal references This is a preliminary step towards deferring shm resize operations until after the compositor has released all external references on a pool. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-shm.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 81bf6571..79c58df8 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -52,7 +52,8 @@ static struct sigaction wl_shm_old_sigbus_action; struct wl_shm_pool { struct wl_resource *resource; - int refcount; + int internal_refcount; + int external_refcount; char *data; int32_t size; }; @@ -73,10 +74,14 @@ struct wl_shm_sigbus_data { }; static void -shm_pool_unref(struct wl_shm_pool *pool) +shm_pool_unref(struct wl_shm_pool *pool, bool external) { - pool->refcount--; - if (pool->refcount) + if (external) + pool->external_refcount--; + else + pool->internal_refcount--; + + if (pool->internal_refcount + pool->external_refcount) return; munmap(pool->data, pool->size); @@ -89,7 +94,7 @@ destroy_buffer(struct wl_resource *resource) struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource); if (buffer->pool) - shm_pool_unref(buffer->pool); + shm_pool_unref(buffer->pool, false); free(buffer); } @@ -162,13 +167,13 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, buffer->stride = stride; buffer->offset = offset; buffer->pool = pool; - pool->refcount++; + pool->internal_refcount++; buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id); if (buffer->resource == NULL) { wl_client_post_no_memory(client); - shm_pool_unref(pool); + shm_pool_unref(pool, false); free(buffer); return; } @@ -183,7 +188,7 @@ destroy_pool(struct wl_resource *resource) { struct wl_shm_pool *pool = wl_resource_get_user_data(resource); - shm_pool_unref(pool); + shm_pool_unref(pool, false); } static void @@ -243,7 +248,8 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, goto err_close; } - pool->refcount = 1; + pool->internal_refcount = 1; + pool->external_refcount = 0; pool->size = size; pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); @@ -396,9 +402,10 @@ wl_shm_buffer_get_height(struct wl_shm_buffer *buffer) WL_EXPORT struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) { - assert(buffer->pool->refcount); + assert(buffer->pool->internal_refcount + + buffer->pool->external_refcount); - buffer->pool->refcount++; + buffer->pool->external_refcount++; return buffer->pool; } @@ -418,7 +425,7 @@ wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) WL_EXPORT void wl_shm_pool_unref(struct wl_shm_pool *pool) { - shm_pool_unref(pool); + shm_pool_unref(pool, true); } static void From ed5f5030cae66576b081f261afb6233ec634f287 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Tue, 9 Feb 2016 16:03:48 -0600 Subject: [PATCH 0287/1152] shm: Defer wl_shm_pool_resize if a pool has external references If a compositor is rendering in one thread while dispatching wayland events in another, a wl_shm_pool_resize() could change the memory mappings it's rendering from and cause a crash. Now we defer wl_shm_pool_resize() if the compositor has references on a pool, and perform the actual resize when it drops those references. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-shm.c | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 79c58df8..be3dd3f1 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -56,6 +56,7 @@ struct wl_shm_pool { int external_refcount; char *data; int32_t size; + int32_t new_size; }; struct wl_shm_buffer { @@ -73,13 +74,36 @@ struct wl_shm_sigbus_data { int fallback_mapping_used; }; +static void +shm_pool_finish_resize(struct wl_shm_pool *pool) +{ + void *data; + + if (pool->size == pool->new_size) + return; + + data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); + if (data == MAP_FAILED) { + wl_resource_post_error(pool->resource, + WL_SHM_ERROR_INVALID_FD, + "failed mremap"); + return; + } + + pool->data = data; + pool->size = pool->new_size; +} + static void shm_pool_unref(struct wl_shm_pool *pool, bool external) { - if (external) + if (external) { pool->external_refcount--; - else + if (pool->external_refcount == 0) + shm_pool_finish_resize(pool); + } else { pool->internal_refcount--; + } if (pool->internal_refcount + pool->external_refcount) return; @@ -202,7 +226,6 @@ shm_pool_resize(struct wl_client *client, struct wl_resource *resource, int32_t size) { struct wl_shm_pool *pool = wl_resource_get_user_data(resource); - void *data; if (size < pool->size) { wl_resource_post_error(resource, @@ -211,16 +234,15 @@ shm_pool_resize(struct wl_client *client, struct wl_resource *resource, return; } - data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE); - if (data == MAP_FAILED) { - wl_resource_post_error(resource, - WL_SHM_ERROR_INVALID_FD, - "failed mremap"); - return; - } + pool->new_size = size; - pool->data = data; - pool->size = size; + /* If the compositor has taken references on this pool it + * may be caching pointers into it. In that case we + * defer the resize (which may move the entire mapping) + * until the compositor finishes dereferencing the pool. + */ + if (pool->external_refcount == 0) + shm_pool_finish_resize(pool); } struct wl_shm_pool_interface shm_pool_interface = { @@ -251,6 +273,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, pool->internal_refcount = 1; pool->external_refcount = 0; pool->size = size; + pool->new_size = size; pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (pool->data == MAP_FAILED) { From 1d6e885b1dd7e481c7975f6641632ef107163482 Mon Sep 17 00:00:00 2001 From: Derek Foreman <derekf@osg.samsung.com> Date: Tue, 9 Feb 2016 16:29:49 -0600 Subject: [PATCH 0288/1152] shm: Log a warning if a shm buffer address is requested when it may be invalid If wl_shm_buffer_get_data() is called on a shm pool that has an external reference and a pending resize, then the buffer may be outside the pool's current mapping. Log a warning if this happens. Signed-off-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-shm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index be3dd3f1..5efbd70d 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -387,6 +387,11 @@ wl_shm_buffer_get_data(struct wl_shm_buffer *buffer) if (!buffer->pool) return NULL; + if (buffer->pool->external_refcount && + (buffer->pool->size != buffer->pool->new_size)) + wl_log("Buffer address requested when its parent pool " + "has an external reference and a deferred resize " + "pending.\n"); return buffer->pool->data + buffer->offset; } From 5192d4c01a1d08d68b0c23663f79b04878bf5c0c Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 10 Mar 2016 14:36:08 -0600 Subject: [PATCH 0289/1152] doc: Ignore html subdirectory. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/doxygen/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/doxygen/.gitignore b/doc/doxygen/.gitignore index 730a1ef0..a85e6c0d 100644 --- a/doc/doxygen/.gitignore +++ b/doc/doxygen/.gitignore @@ -1,3 +1,4 @@ doxygen_sqlite3.db +html/ wayland.doxygen xml/ From 0715ee5cf9c467b0aa2717f6276716d81fd0178b Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 10 Mar 2016 22:31:59 -0600 Subject: [PATCH 0290/1152] ignore: Add *.dtd.embed Although autogen.sh has a --disable-dtd-validation option, it is on by default, so it seems convenient to add the generated symlink to .gitignore. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/src/.gitignore b/src/.gitignore index 4421b46d..128e4f7c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1 +1,2 @@ +*.dtd.embed /wayland-version.h From 5259084288061ad6ef24e41f456f5f6d9ac7f222 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 31 Mar 2016 18:55:54 -0500 Subject: [PATCH 0291/1152] scanner: Fix spacing of @param Adds one space to the @param lines in generated .h files, aligning the indentation with the rest of the comment block. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index a895f92a..65df3aee 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1148,7 +1148,7 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface) " * Sends an %s event to the client owning the resource.\n", interface->name, m->name); - printf("* @param resource_ The client's resource\n"); + printf(" * @param resource_ The client's resource\n"); wl_list_for_each(a, &m->arg_list, link) { if (a->summary) printf(" * @param %s %s\n", a->name, a->summary); From e40a46ca210aefa14b8dcc2d6dd233bcc06ba00b Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Sat, 2 Apr 2016 17:04:04 +0100 Subject: [PATCH 0292/1152] protocol: fix spelling mistake Signed-off-by: Eric Engestrom <eric@engestrom.ch> --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8739cd31..12a6efd1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2038,7 +2038,7 @@ The timestamp is to be interpreted identical to the timestamp in the wl_pointer.axis event. The timestamp value may be the same as a - preceeding wl_pointer.axis event. + preceding wl_pointer.axis event. </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> <arg name="axis" type="uint" enum="axis" summary="the axis stopped with this event"/> From ae78dcb1ada6033419edcfc93074407518640e42 Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Sat, 2 Apr 2016 17:04:05 +0100 Subject: [PATCH 0293/1152] wayland-client: fix spelling mistake Signed-off-by: Eric Engestrom <eric@engestrom.ch> --- src/wayland-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 297c7a5f..33033e71 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1587,7 +1587,7 @@ wl_display_poll(struct wl_display *display, short int events) * the appropriate event queues. Finally, events on given event queue are * dispatched. On failure -1 is returned and errno set appropriately. * - * In a multi threaded enviroment, do not manually wait using poll() (or + * In a multi threaded environment, do not manually wait using poll() (or * equivalent) before calling this function, as doing so might cause a dead * lock. If external reliance on poll() (or equivalent) is required, see * wl_display_prepare_read_queue() of how to do so. @@ -1692,7 +1692,7 @@ wl_display_dispatch_queue_pending(struct wl_display *display, * the appropriate event queues. Finally, events on the default event queue * are dispatched. On failure -1 is returned and errno set appropriately. * - * In a multi threaded enviroment, do not manually wait using poll() (or + * In a multi threaded environment, do not manually wait using poll() (or * equivalent) before calling this function, as doing so might cause a dead * lock. If external reliance on poll() (or equivalent) is required, see * wl_display_prepare_read_queue() of how to do so. From 05f7aec1d59be56e8f5aaf5445266ac80336dab2 Mon Sep 17 00:00:00 2001 From: Emil Velikov <emil.l.velikov@gmail.com> Date: Sun, 17 Apr 2016 12:29:22 +0100 Subject: [PATCH 0294/1152] scanner: move include directives before extern "C" wrapper Adding extern "C" wrapper before includes (especially system ones) is illadvised as the headers themselves can behave diffently in that case. See the section "Including C Headers in C++ Code" in the following http://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> --- src/scanner.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 65df3aee..52c07a6c 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1423,13 +1423,13 @@ emit_header(struct protocol *protocol, enum side side) printf("#ifndef %s_%s_PROTOCOL_H\n" "#define %s_%s_PROTOCOL_H\n" "\n" + "#include <stdint.h>\n" + "#include <stddef.h>\n" + "#include \"%s\"\n\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n" "\n" - "#include <stdint.h>\n" - "#include <stddef.h>\n" - "#include \"%s\"\n\n" "struct wl_client;\n" "struct wl_resource;\n\n", protocol->uppercase_name, s, From 897509bc6af0530cb06fa04e05bf6b6c13df8d48 Mon Sep 17 00:00:00 2001 From: Emil Velikov <emil.l.velikov@gmail.com> Date: Sun, 17 Apr 2016 12:29:23 +0100 Subject: [PATCH 0295/1152] server: move include directives before extern "C" wrapper Analogous to previous commit but for the server(-core) header. Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> --- src/wayland-server-core.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index e8e1e9c2..fa7f3945 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -26,15 +26,15 @@ #ifndef WAYLAND_SERVER_CORE_H #define WAYLAND_SERVER_CORE_H -#ifdef __cplusplus -extern "C" { -#endif - #include <sys/types.h> #include <stdint.h> #include "wayland-util.h" #include "wayland-version.h" +#ifdef __cplusplus +extern "C" { +#endif + enum { WL_EVENT_READABLE = 0x01, WL_EVENT_WRITABLE = 0x02, From 2c8da324844b7ac95b39077efa1af762a22bf619 Mon Sep 17 00:00:00 2001 From: Emil Velikov <emil.l.velikov@gmail.com> Date: Sun, 17 Apr 2016 12:29:24 +0100 Subject: [PATCH 0296/1152] utils: move include directives before extern "C" wrapper Analogous to last two commits. Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> --- src/wayland-util.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 35b50ea7..cc1999d6 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -31,15 +31,15 @@ #ifndef WAYLAND_UTIL_H #define WAYLAND_UTIL_H -#ifdef __cplusplus -extern "C" { -#endif - #include <math.h> #include <stddef.h> #include <inttypes.h> #include <stdarg.h> +#ifdef __cplusplus +extern "C" { +#endif + /* GCC visibility */ #if defined(__GNUC__) && __GNUC__ >= 4 #define WL_EXPORT __attribute__ ((visibility("default"))) From 70850643f37d1b74f47affd0174101bf1f7fd2a8 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Tue, 5 Apr 2016 18:24:01 -0500 Subject: [PATCH 0297/1152] protocol: Correct grammar and spelling Fix grammar, spelling, tense, and other inconsistencies, based on correctness, consistency, and precedence both here and influenced by wayland-protocols. - Standardize lower case for summary attribute values. - Minor vertical whitespace removal consistency. - Standarize references to coordinates, preferring 'surface local' - Fix spelling, grammar, tense, and punctuation. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> --- protocol/wayland.xml | 181 +++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 92 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 12a6efd1..164ec03b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -67,7 +67,7 @@ where the error occurred, most often in response to a request to that object. The code identifies the error and is defined by the object interface. As such, each interface defines its - own set of error codes. The message is an brief description + own set of error codes. The message is a brief description of the error, for (debugging) convenience. </description> <arg name="object_id" type="object"/> @@ -93,7 +93,7 @@ This event is used internally by the object ID management logic. When a client deletes an object, the server will send this event to acknowledge that it has seen the delete request. - When the client receive this event, it will know that it can + When the client receives this event, it will know that it can safely reuse the object ID. </description> <arg name="id" type="uint" /> @@ -214,8 +214,8 @@ Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has - width and height as specified. The stride arguments specifies - the number of bytes from beginning of one row to the beginning + width and height as specified. The stride argument specifies + the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. @@ -392,13 +392,13 @@ <event name="release"> <description summary="compositor releases buffer"> Sent when this wl_buffer is no longer used by the compositor. - The client is now free to re-use or destroy this buffer and its + The client is now free to reuse or destroy this buffer and its backing storage. If a client receives a release event before the frame callback requested in the same wl_surface.commit that attaches this wl_buffer to a surface, then the client is immediately free to - re-use the buffer and its backing storage, and does not need a + reuse the buffer and its backing storage, and does not need a second buffer for the next surface content update. Typically this is possible, when the compositor maintains a copy of the wl_surface contents, e.g. as a GL texture. This is an important @@ -464,7 +464,7 @@ EOF and then closes its end, at which point the transfer is complete. - This request may happen multiple times for different mimetypes, + This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance. @@ -511,7 +511,7 @@ Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor - need to change the selected action. + needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter @@ -585,7 +585,7 @@ compositor shall no longer be able to induce a different action. Upon "ask" actions, it is expected that the drag-and-drop destination - may potentially choose different a different action and/or mime type, + may potentially choose a different action and/or mime type, based on wl_data_offer.source_actions and finally chosen by the user (e.g. popping up a menu with the available options). The final wl_data_offer.set_actions and wl_data_offer.accept requests @@ -654,7 +654,7 @@ - The data source has been replaced by another data source. - The drag-and-drop operation was performed, but the drop destination - did not accept any of the mimetypes offered through + did not accept any of the mime types offered through wl_data_source.target. - The drag-and-drop operation was performed, but the drop destination did not select any of the actions present in the mask offered through @@ -697,7 +697,7 @@ <description summary="the drag-and-drop operation physically finished"> The user performed the drop action. This event does not indicate acceptance, wl_data_source.cancelled may still be emitted afterwards - if the drop destination does not accept any mimetype. + if the drop destination does not accept any mime type. However, this event might however not be received if the compositor cancelled the drag-and-drop operation before this event could happen. @@ -860,7 +860,7 @@ </event> <event name="drop"> - <description summary="end drag-and-drag session successfully"> + <description summary="end drag-and-drop session successfully"> The event is sent when a drag-and-drop operation is ended because the implicit grab is removed. @@ -946,7 +946,7 @@ (source actions ∩ destination actions). In addition, compositors may also pick different actions in - reaction to key modifiers being pressed, one common design that + reaction to key modifiers being pressed. One common design that is used in major toolkits (and the behavior recommended for compositors) is: @@ -994,7 +994,6 @@ </interface> <interface name="wl_shell_surface" version="1"> - <description summary="desktop-style metadata interface"> An interface that may be implemented by a wl_surface, for implementations that provide a desktop-style user interface. @@ -1004,7 +1003,7 @@ metadata like title and class, etc. On the server side the object is automatically destroyed when - the related wl_surface is destroyed. On client side, + the related wl_surface is destroyed. On the client side, wl_shell_surface_destroy() must be called before destroying the wl_surface object. </description> @@ -1080,7 +1079,7 @@ <description summary="make the surface a transient surface"> Map the surface relative to an existing surface. - The x and y arguments specify the locations of the upper left + The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface local coordinates. @@ -1121,7 +1120,7 @@ The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 - indicates that the app does not care about framerate. The + indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of @@ -1159,12 +1158,12 @@ be unmapped). The popup grab continues until the window is destroyed or a - mouse button is pressed in any other clients window. A click - in any of the clients surfaces is reported as normal, however, - clicks in other clients surfaces will be discarded and trigger + mouse button is pressed in any other client's window. A click + in any of the client's surfaces is reported as normal, however, + clicks in other clients' surfaces will be discarded and trigger the callback. - The x and y arguments specify the locations of the upper left + The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface local coordinates. </description> @@ -1192,7 +1191,7 @@ on the next buffer attach to this surface. A maximized surface typically fills the entire output it is - bound to, except for desktop element such as panels. This is + bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. @@ -1279,7 +1278,7 @@ local coordinates of the pixel content, in case a buffer_transform or a buffer_scale is used. - A surface without a "role" is fairly useless, a compositor does + A surface without a "role" is fairly useless: a compositor does not know where, when or how to present it. The role is the purpose of a wl_surface. Examples of roles are a cursor for a pointer (as set by wl_pointer.set_cursor), a drag icon @@ -1355,7 +1354,7 @@ any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, - the client may re-use the wl_buffer. A wl_buffer that has been + the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. @@ -1394,7 +1393,7 @@ damage as it repaints the surface. Alternatively, damage can be posted with wl_surface.damage_buffer - which uses buffer co-ordinates instead of surface co-ordinates, + which uses buffer coordinates instead of surface coordinates, and is probably the preferred and intuitive way of doing this. </description> @@ -1406,7 +1405,7 @@ <request name="frame"> <description summary="request a frame throttling hint"> - Request a notification when it is a good time start drawing a new + Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. @@ -1425,10 +1424,10 @@ will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client - to draw and commit after sending the frame callback events to let them + to draw and commit after sending the frame callback events to let it hit the next output refresh. - A server should avoid signalling the frame callbacks if the + A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. @@ -1449,7 +1448,7 @@ opaque content. The opaque region is an optimization hint for the compositor - that lets it optimize out redrawing of content behind opaque + that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. @@ -1465,7 +1464,7 @@ wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. - The initial value for opaque region is empty. Setting the pending + The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty. @@ -1493,7 +1492,7 @@ except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. - The initial value for input region is infinite. That means the + The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set @@ -1506,13 +1505,13 @@ <request name="commit"> <description summary="commit pending surface state"> Surface state (input, opaque, and damage regions, attached buffers, - etc.) is double-buffered. Protocol requests modify the pending - state, as opposed to current state in use by the compositor. Commit + etc.) is double-buffered. Protocol requests modify the pending state, + as opposed to the current state in use by the compositor. A commit request atomically applies all pending state, replacing the current state. After commit, the new pending state is as documented for each related request. - On commit, a pending wl_buffer is applied first, all other state + On commit, a pending wl_buffer is applied first, and all other state second. This means that all coordinates in double-buffered state are relative to the new wl_buffer coming into use, except for wl_surface.attach itself. If there is no pending wl_buffer, the @@ -1564,7 +1563,7 @@ values are never changed. The purpose of this request is to allow clients to render content - according to the output transform, thus permiting the compositor to + according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are @@ -1598,9 +1597,9 @@ Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher - resolution buffer data for use on high resolution outputs. Its - intended that you pick the same buffer scale as the scale of the - output that the surface is displayed on.This means the compositor + resolution buffer data for use on high resolution outputs. It is + intended that you pick the same buffer scale as the scale of the + output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach @@ -1615,7 +1614,7 @@ <!-- Version 4 additions --> <request name="damage_buffer" since="4"> - <description summary="mark part of the surface damaged using buffer co-ordinates"> + <description summary="mark part of the surface damaged using buffer coordinates"> This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor @@ -1634,14 +1633,14 @@ damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it - takes damage in buffer co-ordinates instead of surface local - co-ordinates. While this generally is more intuitive than surface - co-ordinates, it is especially desirable when using wp_viewport + takes damage in buffer coordinates instead of surface local + coordinates. While this generally is more intuitive than surface + coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may - be interleaved in the protocol stream, It is impossible to determine + be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the @@ -1669,9 +1668,9 @@ This is a bitmask of capabilities this seat has; if a member is set, then it is present on the seat. </description> - <entry name="pointer" value="1" summary="The seat has pointer devices"/> - <entry name="keyboard" value="2" summary="The seat has one or more keyboards"/> - <entry name="touch" value="4" summary="The seat has touch devices"/> + <entry name="pointer" value="1" summary="the seat has pointer devices"/> + <entry name="keyboard" value="2" summary="the seat has one or more keyboards"/> + <entry name="touch" value="4" summary="the seat has touch devices"/> </enum> <event name="capabilities"> @@ -1758,7 +1757,7 @@ <request name="release" type="destructor" since="5"> <description summary="release the seat object"> - Using this request client can tell the server that it is not going to + Using this request a client can tell the server that it is not going to use the seat object anymore. </description> </request> @@ -1818,8 +1817,8 @@ <arg name="serial" type="uint" summary="serial of the enter event"/> <arg name="surface" type="object" interface="wl_surface" allow-null="true"/> - <arg name="hotspot_x" type="int" summary="x coordinate in surface-relative coordinates"/> - <arg name="hotspot_y" type="int" summary="y coordinate in surface-relative coordinates"/> + <arg name="hotspot_x" type="int" summary="x coordinate in surface local coordinates"/> + <arg name="hotspot_y" type="int" summary="y coordinate in surface local coordinates"/> </request> <event name="enter"> @@ -1827,15 +1826,15 @@ Notification that this seat's pointer is focused on a certain surface. - When an seat's focus enters a surface, the pointer image + When a seat's focus enters a surface, the pointer image is undefined and a client should respond to this event by setting an appropriate pointer image with the set_cursor request. </description> <arg name="serial" type="uint"/> <arg name="surface" type="object" interface="wl_surface"/> - <arg name="surface_x" type="fixed" summary="x coordinate in surface-relative coordinates"/> - <arg name="surface_y" type="fixed" summary="y coordinate in surface-relative coordinates"/> + <arg name="surface_x" type="fixed" summary="x coordinate in surface local coordinates"/> + <arg name="surface_y" type="fixed" summary="y coordinate in surface local coordinates"/> </event> <event name="leave"> @@ -1858,17 +1857,17 @@ </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="surface_x" type="fixed" summary="x coordinate in surface-relative coordinates"/> - <arg name="surface_y" type="fixed" summary="y coordinate in surface-relative coordinates"/> + <arg name="surface_x" type="fixed" summary="x coordinate in surface local coordinates"/> + <arg name="surface_y" type="fixed" summary="y coordinate in surface local coordinates"/> </event> <enum name="button_state"> <description summary="physical button state"> - Describes the physical state of a button which provoked the button + Describes the physical state of a button that produced the button event. </description> - <entry name="released" value="0" summary="The button is not pressed"/> - <entry name="pressed" value="1" summary="The button is pressed"/> + <entry name="released" value="0" summary="the button is not pressed"/> + <entry name="pressed" value="1" summary="the button is pressed"/> </enum> <event name="button"> @@ -1911,7 +1910,7 @@ choose to emit scroll events where the motion vector is equivalent to a motion event vector. - When applicable, clients can transform its view relative to the + When applicable, a client can transform its content relative to the scroll distance. </description> @@ -1924,10 +1923,10 @@ <request name="release" type="destructor" since="3"> <description summary="release the pointer object"> - Using this request client can tell the server that it is not going to + Using this request a client can tell the server that it is not going to use the pointer object anymore. - This request destroys the pointer proxy object, so user must not call + This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request. </description> </request> @@ -1952,7 +1951,7 @@ When a wl_pointer.axis and a wl_pointer.axis_stop event occur within the same frame, this indicates that axis movement in one axis has stopped but continues in the other axis. - When multiple wl_pointer.axis_stop events occur within in the same + When multiple wl_pointer.axis_stop events occur within the same frame, this indicates that these axes stopped in the same instance. A wl_pointer.frame event is sent for every logical event group, @@ -1963,7 +1962,7 @@ The wl_pointer.enter and wl_pointer.leave events are logical events generated by the compositor and not the hardware. These events are also grouped by a wl_pointer.frame. When a pointer moves from one - surface to the another, a compositor should group the + surface to another, a compositor should group the wl_pointer.leave event within the same wl_pointer.frame. However, a client must not rely on wl_pointer.leave and wl_pointer.enter being in the same wl_pointer.frame. @@ -1988,9 +1987,9 @@ the vertical motion of a device is converted to scroll events while a button is held down. </description> - <entry name="wheel" value="0" summary="A physical wheel" /> - <entry name="finger" value="1" summary="Finger on a touch surface" /> - <entry name="continuous" value="2" summary="Continuous coordinate space"/> + <entry name="wheel" value="0" summary="a physical wheel" /> + <entry name="finger" value="1" summary="finger on a touch surface" /> + <entry name="continuous" value="2" summary="continuous coordinate space"/> </enum> <event name="axis_source" since="5"> @@ -2007,7 +2006,7 @@ If the source is wl_pointer axis_source.wheel or wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may - or may not be sent. Whether a compositor sends a axis_stop event + or may not be sent. Whether a compositor sends an axis_stop event for these sources is hardware-specific and implementation-dependent; clients must not rely on receiving an axis_stop event for these scroll sources and should treat scroll sequences from these scroll @@ -2067,7 +2066,7 @@ The discrete value carries the directional information. e.g. a value of -2 is two steps towards the negative direction of this axis. - The axis number is identical to the axis number in the associate + The axis number is identical to the axis number in the associated axis event. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is @@ -2129,7 +2128,7 @@ <enum name="key_state"> <description summary="physical key state"> - Describes the physical state of a key which provoked the key event. + Describes the physical state of a key that produced the key event. </description> <entry name="released" value="0" summary="key is not pressed"/> <entry name="pressed" value="1" summary="key is pressed"/> @@ -2207,23 +2206,23 @@ <event name="down"> <description summary="touch down event and beginning of a touch sequence"> A new touch point has appeared on the surface. This touch point is - assigned a unique @id. Future events from this touchpoint reference + assigned a unique ID. Future events from this touch point reference this ID. The ID ceases to be valid after a touch up event and may be - re-used in the future. + reused in the future. </description> <arg name="serial" type="uint"/> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> <arg name="surface" type="object" interface="wl_surface"/> <arg name="id" type="int" summary="the unique ID of this touch point"/> - <arg name="x" type="fixed" summary="x coordinate in surface-relative coordinates"/> - <arg name="y" type="fixed" summary="y coordinate in surface-relative coordinates"/> + <arg name="x" type="fixed" summary="x coordinate in surface local coordinates"/> + <arg name="y" type="fixed" summary="y coordinate in surface local coordinates"/> </event> <event name="up"> <description summary="end of a touch event sequence"> The touch point has disappeared. No further events will be sent for - this touchpoint and the touch point's ID is released and may be - re-used in a future touch down event. + this touch point and the touch point's ID is released and may be + reused in a future touch down event. </description> <arg name="serial" type="uint"/> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> @@ -2232,12 +2231,12 @@ <event name="motion"> <description summary="update of touch point coordinates"> - A touchpoint has changed coordinates. + A touch point has changed coordinates. </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> <arg name="id" type="int" summary="the unique ID of this touch point"/> - <arg name="x" type="fixed" summary="x coordinate in surface-relative coordinates"/> - <arg name="y" type="fixed" summary="y coordinate in surface-relative coordinates"/> + <arg name="x" type="fixed" summary="x coordinate in surface local coordinates"/> + <arg name="y" type="fixed" summary="y coordinate in surface local coordinates"/> </event> <event name="frame"> @@ -2253,7 +2252,7 @@ particular gesture. Touch cancellation applies to all touch points currently active on this client's surface. The client is responsible for finalizing the touch points, future touch points on - this surface may re-use the touch point ID. + this surface may reuse the touch point ID. </description> </event> @@ -2268,7 +2267,7 @@ <description summary="compositor output region"> An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an - output corresponds to rectangular area in that space that is + output corresponds to a rectangular area in that space that is actually visible. This typically corresponds to a monitor that displays part of the compositor space. This object is published as global during start up, or when a monitor is hotplugged. @@ -2296,7 +2295,7 @@ The flipped values correspond to an initial flip around a vertical axis followed by rotation. - The purpose is mainly to allow clients render accordingly and + The purpose is mainly to allow clients to render accordingly and tell the compositor, so that for fullscreen surfaces, the compositor will still be able to scan out directly from client surfaces. @@ -2361,7 +2360,7 @@ the output device. This is not necessarily the same as the output size in the global compositor space. For instance, the output may be scaled, as described in wl_output.scale, - or transformed , as described in wl_output.transform. + or transformed, as described in wl_output.transform. </description> <arg name="flags" type="uint" enum="mode" summary="bitfield of mode flags"/> <arg name="width" type="int" summary="width of the mode in hardware units"/> @@ -2371,7 +2370,7 @@ <event name="done" since="2"> <description summary="sent all information about output"> - This event is sent after all other properties has been + This event is sent after all other properties have been sent after binding to the output object and after any other property changes done after that. This allows changes to the output properties to be seen as @@ -2439,7 +2438,6 @@ <arg name="width" type="int"/> <arg name="height" type="int"/> </request> - </interface> <interface name="wl_subcompositor" version="1"> @@ -2490,7 +2488,7 @@ </description> <arg name="id" type="new_id" interface="wl_subsurface" - summary="the new subsurface object id"/> + summary="the new subsurface object ID"/> <arg name="surface" type="object" interface="wl_surface" summary="the surface to be turned into a sub-surface"/> <arg name="parent" type="object" interface="wl_surface" @@ -2512,7 +2510,7 @@ hidden, or if a NULL wl_buffer is applied. These rules apply recursively through the tree of surfaces. - The behaviour of wl_surface.commit request on a sub-surface + The behaviour of a wl_surface.commit request on a sub-surface depends on the sub-surface's mode. The possible modes are synchronized and desynchronized, see methods wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized @@ -2554,7 +2552,7 @@ <request name="destroy" type="destructor"> <description summary="remove sub-surface interface"> The sub-surface interface is removed from the wl_surface object - that was turned into a sub-surface with + that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted, and the wl_surface loses its role as a sub-surface. The wl_surface is unmapped. @@ -2569,7 +2567,7 @@ <request name="set_position"> <description summary="reposition the sub-surface"> This schedules a sub-surface position change. - The sub-surface will be moved so, that its origin (top-left + The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. @@ -2586,8 +2584,8 @@ The initial position is 0, 0. </description> - <arg name="x" type="int" summary="coordinate in the parent surface"/> - <arg name="y" type="int" summary="coordinate in the parent surface"/> + <arg name="x" type="int" summary="x coordinate in the parent surface"/> + <arg name="y" type="int" summary="y coordinate in the parent surface"/> </request> <request name="place_above"> @@ -2615,7 +2613,7 @@ <request name="place_below"> <description summary="restack the sub-surface"> - The sub-surface is placed just below of the reference surface. + The sub-surface is placed just below the reference surface. See wl_subsurface.place_above. </description> @@ -2654,7 +2652,7 @@ If cached state exists when wl_surface.commit is called in desynchronized mode, the pending state is added to the cached - state, and applied as whole. This invalidates the cache. + state, and applied as a whole. This invalidates the cache. Note: even if a sub-surface is set to desynchronized, a parent sub-surface may override it to behave as synchronized. For details, @@ -2664,7 +2662,6 @@ the cached state is applied on set_desync. </description> </request> - </interface> </protocol> From 85b80f5cf059e4e6dbcdea44679d14d5b91548cf Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Fri, 22 Apr 2016 17:46:00 +0200 Subject: [PATCH 0298/1152] connection: remove redundant assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the code is something like: if (object == NULL && ...) { object = NULL; return; } first, the object is already NULL, second, the assignment has no effect since we return from the function right away Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> --- src/connection.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index c0e322fb..747229e5 100644 --- a/src/connection.c +++ b/src/connection.c @@ -838,7 +838,6 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) } else if (object == NULL && id != 0) { wl_log("unknown object (%u), message %s(%s)\n", id, message->name, message->signature); - object = NULL; errno = EINVAL; return -1; } From 9a652c44f7fb9ce6894a41a87d8fe571ad59969d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Wed, 27 Apr 2016 14:46:54 +0800 Subject: [PATCH 0299/1152] client: Make proxy_destroy a static function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit proxy_destroy() is just the implementation of the atomic part of wl_proxy_destroy(), so lets make it static. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-client.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 33033e71..0c2ab323 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -252,9 +252,6 @@ decrease_closure_args_refcount(struct wl_closure *closure) } } -void -proxy_destroy(struct wl_proxy *proxy); - static void wl_event_queue_release(struct wl_event_queue *queue) { @@ -404,7 +401,7 @@ wl_proxy_create_for_id(struct wl_proxy *factory, return proxy; } -void +static void proxy_destroy(struct wl_proxy *proxy) { if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) From 6d29c0da3cd168e08187cd204d2314188479c0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Fri, 29 Apr 2016 19:30:22 +0800 Subject: [PATCH 0300/1152] client: Introduce proxy wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the libwayland-client client API with multiple threads with thread local queues are prone to race conditions. The problem is that one thread can read and queue events after another thread creates a proxy but before it sets the queue. This may result in the event to the proxy being silently dropped, or potentially dispatched on the wrong thread had the creating thread set the implementation before setting the queue. This patch introduces API to solve this case by introducing "proxy wrappers". In short, a proxy wrapper is a wl_proxy struct that will never itself proxy any events, but may be used by the client to set a queue, and use it instead of the original proxy when sending requests that creates new proxies. When sending requests, the wrapper will work in the same way as the normal proxy object, but the proxy created by sending a request (for example wl_display.sync) will inherit to the same proxy queue as the wrapper. https://bugs.freedesktop.org/show_bug.cgi?id=91273 Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/wayland-client-core.h | 6 +++ src/wayland-client.c | 110 +++++++++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 91f7e7b8..b1d65155 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -132,6 +132,12 @@ struct wl_proxy * wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface); +void * +wl_proxy_create_wrapper(void *proxy); + +void +wl_proxy_wrapper_destroy(void *proxy_wrapper); + struct wl_proxy * wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, diff --git a/src/wayland-client.c b/src/wayland-client.c index 0c2ab323..867adeae 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -51,7 +51,8 @@ enum wl_proxy_flag { WL_PROXY_FLAG_ID_DELETED = (1 << 0), - WL_PROXY_FLAG_DESTROYED = (1 << 1) + WL_PROXY_FLAG_DESTROYED = (1 << 1), + WL_PROXY_FLAG_WRAPPER = (1 << 2), }; struct wl_proxy { @@ -425,6 +426,8 @@ proxy_destroy(struct wl_proxy *proxy) * * \param proxy The proxy to be destroyed * + * \c proxy must not be a proxy wrapper. + * * \memberof wl_proxy */ WL_EXPORT void @@ -432,6 +435,9 @@ wl_proxy_destroy(struct wl_proxy *proxy) { struct wl_display *display = proxy->display; + if (proxy->flags & WL_PROXY_FLAG_WRAPPER) + wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n"); + pthread_mutex_lock(&display->mutex); proxy_destroy(proxy); pthread_mutex_unlock(&display->mutex); @@ -452,12 +458,17 @@ wl_proxy_destroy(struct wl_proxy *proxy) * \c n, \c implementation[n] should point to the handler of \c n for * the given object. * + * \c proxy must not be a proxy wrapper. + * * \memberof wl_proxy */ WL_EXPORT int wl_proxy_add_listener(struct wl_proxy *proxy, void (**implementation)(void), void *data) { + if (proxy->flags & WL_PROXY_FLAG_WRAPPER) + wl_abort("Proxy %p is a wrapper\n", proxy); + if (proxy->object.implementation || proxy->dispatcher) { wl_log("proxy %p already has listener\n", proxy); return -1; @@ -504,6 +515,8 @@ wl_proxy_get_listener(struct wl_proxy *proxy) * The exact details of dispatcher_data depend on the dispatcher used. This * function is intended to be used by language bindings, not user code. * + * \c proxy must not be a proxy wrapper. + * * \memberof wl_proxy */ WL_EXPORT int @@ -511,6 +524,9 @@ wl_proxy_add_dispatcher(struct wl_proxy *proxy, wl_dispatcher_func_t dispatcher, const void *implementation, void *data) { + if (proxy->flags & WL_PROXY_FLAG_WRAPPER) + wl_abort("Proxy %p is a wrapper\n", proxy); + if (proxy->object.implementation || proxy->dispatcher) { wl_log("proxy %p already has listener\n", proxy); return -1; @@ -1952,6 +1968,98 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) proxy->queue = &proxy->display->default_queue; } +/** Create a proxy wrapper for making queue assignments thread-safe + * + * \param proxy The proxy object to be wrapped + * \return A proxy wrapper for the given proxy or NULL on failure + * + * A proxy wrapper is type of 'struct wl_proxy' instance that can be used when + * sending requests instead of using the original proxy. A proxy wrapper does + * not have an implementation or dispatcher, and events received on the + * object is still emitted on the original proxy. Trying to set an + * implementation or dispatcher will have no effect but result in a warning + * being logged. + * + * Setting the proxy queue of the proxy wrapper will make new objects created + * using the proxy wrapper use the set proxy queue. + * Even though there is no implementation nor dispatcher, the proxy queue can + * be changed. This will affect the default queue of new objects created by + * requests sent via the proxy wrapper. + * + * A proxy wrapper can only be destroyed using wl_proxy_wrapper_destroy(). + * + * A proxy wrapper must be destroyed before the proxy it was created from. + * + * If a user reads and dispatches events on more than one thread, it is + * necessary to use a proxy wrapper when sending requests on objects when the + * intention is that a newly created proxy is to use a proxy queue different + * from the proxy the request was sent on, as creating the new proxy and then + * setting the queue is not thread safe. + * + * For example, a module that runs using its own proxy queue that needs to + * do display roundtrip must wrap the wl_display proxy object before sending + * the wl_display.sync request. For example: + * + * \code + * + * struct wl_event_queue *queue = ...; + * struct wl_display *wrapped_display; + * struct wl_callback *callback; + * + * wrapped_display = wl_proxy_create_wrapper(display); + * wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue); + * callback = wl_display_sync(wrapped_display); + * wl_proxy_wrapper_destroy(wrapped_display); + * wl_callback_add_listener(callback, ...); + * + * \endcode + * + * \memberof wl_proxy + */ +WL_EXPORT void * +wl_proxy_create_wrapper(void *proxy) +{ + struct wl_proxy *wrapped_proxy = proxy; + struct wl_proxy *wrapper; + + wrapper = zalloc(sizeof *wrapper); + if (!wrapper) + return NULL; + + pthread_mutex_lock(&wrapped_proxy->display->mutex); + + wrapper->object.interface = wrapped_proxy->object.interface; + wrapper->object.id = wrapped_proxy->object.id; + wrapper->version = wrapped_proxy->version; + wrapper->display = wrapped_proxy->display; + wrapper->queue = wrapped_proxy->queue; + wrapper->flags = WL_PROXY_FLAG_WRAPPER; + wrapper->refcount = 1; + + pthread_mutex_unlock(&wrapped_proxy->display->mutex); + + return wrapper; +} + +/** Destroy a proxy wrapper + * \param proxy_wrapper The proxy wrapper to be destroyed + * + * \memberof wl_proxy + */ +WL_EXPORT void +wl_proxy_wrapper_destroy(void *proxy_wrapper) +{ + struct wl_proxy *wrapper = proxy_wrapper; + + if (!(wrapper->flags & WL_PROXY_FLAG_WRAPPER)) + wl_abort("Tried to destroy non-wrapper proxy with " + "wl_proxy_wrapper_destroy\n"); + + assert(wrapper->refcount == 1); + + free(wrapper); +} + WL_EXPORT void wl_log_set_handler_client(wl_log_func_t handler) { From 69ec70fb0d3f75f4bcce449238d6297f6a986b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Fri, 29 Apr 2016 19:30:23 +0800 Subject: [PATCH 0301/1152] tests/queue-test: Add tests for proxy wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test that doing wl_display.sync on a wrapped proxy with a special queue works as expected. Test that creating a wrapper on a destroyed but not freed proxy fails. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- tests/queue-test.c | 122 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/tests/queue-test.c b/tests/queue-test.c index 02865aec..932bc555 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -204,6 +204,104 @@ client_test_queue_roundtrip(void) wl_display_disconnect(display); } +static void +client_test_queue_proxy_wrapper(void) +{ + struct wl_event_queue *queue; + struct wl_display *display; + struct wl_display *display_wrapper; + struct wl_callback *callback; + bool done = false; + + /* + * For an illustration of what usage would normally fail without using + * proxy wrappers, see the `client_test_queue_set_queue_race' test case. + */ + + display = wl_display_connect(NULL); + assert(display); + + /* Pretend we are in a separate thread where a thread-local queue is + * used. */ + queue = wl_display_create_queue(display); + assert(queue); + + display_wrapper = wl_proxy_create_wrapper(display); + assert(display_wrapper); + wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); + callback = wl_display_sync(display_wrapper); + wl_proxy_wrapper_destroy(display_wrapper); + assert(callback != NULL); + + /* Pretend we are now another thread and dispatch the dispatch the main + * queue while also knowing our callback is read and queued. */ + wl_display_roundtrip(display); + + /* Make sure that the pretend-to-be main thread didn't dispatch our + * callback, behind our back. */ + wl_callback_add_listener(callback, &sync_listener_roundtrip, &done); + wl_display_flush(display); + + assert(!done); + + /* Make sure that we eventually end up dispatching our callback. */ + while (!done) + assert(wl_display_dispatch_queue(display, queue) != -1); + + wl_callback_destroy(callback); + wl_event_queue_destroy(queue); + + wl_display_disconnect(display); +} + +static void +client_test_queue_set_queue_race(void) +{ + struct wl_event_queue *queue; + struct wl_display *display; + struct wl_callback *callback; + bool done = false; + + /* + * This test illustrates the multi threading scenario which would fail + * without doing what is done in the `client_test_queue_proxy_wrapper' + * test. + */ + + display = wl_display_connect(NULL); + assert(display); + + /* Pretend we are in a separate thread where a thread-local queue is + * used. */ + queue = wl_display_create_queue(display); + assert(queue); + + callback = wl_display_sync(display); + assert(callback != NULL); + + /* Pretend we are now another thread and dispatch the dispatch the main + * queue while also knowing our callback is read, queued on the wrong + * queue, and dispatched. */ + wl_display_roundtrip(display); + + /* Pretend we are back in the separate thread, and continue with setting + * up our callback. */ + wl_callback_add_listener(callback, &sync_listener_roundtrip, &done); + wl_proxy_set_queue((struct wl_proxy *) callback, queue); + + /* Roundtrip our separate thread queue to make sure any events are + * dispatched. */ + wl_display_roundtrip_queue(display, queue); + + /* Verify that the callback has indeed been dropped. */ + assert(!done); + + wl_callback_destroy(callback); + wl_event_queue_destroy(queue); + + wl_display_disconnect(display); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -259,3 +357,27 @@ TEST(queue_roundtrip) display_destroy(d); } + +TEST(queue_set_queue_proxy_wrapper) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_proxy_wrapper); + display_run(d); + + display_destroy(d); +} + +TEST(queue_set_queue_race) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_set_queue_race); + display_run(d); + + display_destroy(d); +} From 6fe12f02e3b4879cd3d5faa08f023cc761d13be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> Date: Wed, 27 Apr 2016 15:37:41 +0800 Subject: [PATCH 0302/1152] client: Fix wl_display_roundtrip_queue() race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this commit, wl_display_roundtrip_queue() is vulnerable to a race condition, causing the callback to be dispatched on the wrong queue. The race condition happens if some non-main thread calls wl_display_roundtrip_queue() with its thread local queue, and the main thread reads and dispatches the callback event from the wl_display_sync() call before the thread local queue is set. The issue is fixed by using a proxy wrapper, making the initialization of the callback proxy atomic, effectively making it no longer possible for some other thread to dispatch the proxy before the correct thread local queue is set. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> [Pekka: check display_wrapper] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-client.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 867adeae..7af806ce 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1099,14 +1099,23 @@ static const struct wl_callback_listener sync_listener = { WL_EXPORT int wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue) { + struct wl_display *display_wrapper; struct wl_callback *callback; int done, ret = 0; done = 0; - callback = wl_display_sync(display); + + display_wrapper = wl_proxy_create_wrapper(display); + if (!display_wrapper) + return -1; + + wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); + callback = wl_display_sync(display_wrapper); + wl_proxy_wrapper_destroy(display_wrapper); + if (callback == NULL) return -1; - wl_proxy_set_queue((struct wl_proxy *) callback, queue); + wl_callback_add_listener(callback, &sync_listener, &done); while (!done && ret >= 0) ret = wl_display_dispatch_queue(display, queue); From 3178200f0d0c6f4bfe9cd90dbc80608366861a4c Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 28 Apr 2016 12:01:33 -0500 Subject: [PATCH 0303/1152] doc: Hyphenate compound adjectives window-local, surface-local See https://lists.freedesktop.org/archives/wayland-devel/2016-April/028249.html. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/publican/sources/Architecture.xml | 4 ++-- doc/publican/sources/Protocol.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/publican/sources/Architecture.xml b/doc/publican/sources/Architecture.xml index 5d9ada0c..b8a104cf 100644 --- a/doc/publican/sources/Architecture.xml +++ b/doc/publican/sources/Architecture.xml @@ -114,7 +114,7 @@ As suggested above, there are a few problems with this approach. The X server doesn't have the information to decide which window should receive the event, nor can it - transform the screen coordinates to window local + transform the screen coordinates to window-local coordinates. And even though X has handed responsibility for the final painting of the screen to the compositing manager, X still controls the front buffer and modesetting. Most of @@ -172,7 +172,7 @@ in the scenegraph. Thus, the compositor can pick the right window and transform the screen coordinates - to window local coordinates, by + to window-local coordinates, by applying the inverse transformations. The types of transformation that can be applied diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 66cebfb6..481e1756 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -333,7 +333,7 @@ A seat represents a group of input devices including mice, keyboards and touchscreens. It has a keyboard and pointer focus. Seats are global objects. Pointer events are delivered - in surface local coordinates. + in surface-local coordinates. </para> <para> The compositor maintains an implicit grab when a button is From 4db76023f8ab724a1bc3cb58f3f4e4d19aa70af2 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 28 Apr 2016 12:01:34 -0500 Subject: [PATCH 0304/1152] protocol: Hyphenate compound adjective surface-local Remove superfluous 'local' from 'buffer local'. In addition, simplify the phrasing of local x/y coordinates in parameter summaries. See https://lists.freedesktop.org/archives/wayland-devel/2016-April/028249.html. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 50 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 164ec03b..378879e4 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -828,8 +828,8 @@ <description summary="initiate drag-and-drop session"> This event is sent when an active drag-and-drop pointer enters a surface owned by the client. The position of the pointer at - enter time is provided by the x and y arguments, in surface - local coordinates. + enter time is provided by the x and y arguments, in surface-local + coordinates. </description> <arg name="serial" type="uint"/> @@ -851,7 +851,7 @@ <description summary="drag-and-drop session motion"> This event is sent when the drag-and-drop pointer moves within the currently focused surface. The new position of the pointer - is provided by the x and y arguments, in surface local + is provided by the x and y arguments, in surface-local coordinates. </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> @@ -1081,7 +1081,7 @@ The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the - parent surface, in surface local coordinates. + parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour. </description> @@ -1165,7 +1165,7 @@ The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the - parent surface, in surface local coordinates. + parent surface, in surface-local coordinates. </description> <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> @@ -1251,7 +1251,7 @@ event it received. The width and height arguments specify the size of the window - in surface local coordinates. + in surface-local coordinates. </description> <arg name="edges" type="uint" enum="resize"/> @@ -1274,8 +1274,8 @@ It has a location, size and pixel contents. The size of a surface (and relative positions on it) is described - in surface local coordinates, which may differ from the buffer - local coordinates of the pixel content, in case a buffer_transform + in surface-local coordinates, which may differ from the buffer + coordinates of the pixel content, in case a buffer_transform or a buffer_scale is used. A surface without a "role" is fairly useless: a compositor does @@ -1336,7 +1336,7 @@ The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper - left corner, in surface local coordinates. In other words, the + left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. @@ -1382,7 +1382,7 @@ Damage is double-buffered state, see wl_surface.commit. - The damage rectangle is specified in surface local coordinates. + The damage rectangle is specified in surface-local coordinates. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage @@ -1453,7 +1453,7 @@ behaviour, but marking transparent content as opaque will result in repaint artifacts. - The opaque region is specified in surface local coordinates. + The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. @@ -1482,7 +1482,7 @@ surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. - The input region is specified in surface local coordinates. + The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. @@ -1633,7 +1633,7 @@ damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it - takes damage in buffer coordinates instead of surface local + takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale @@ -1796,8 +1796,8 @@ The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), - where (x, y) are the coordinates of the pointer location, in surface - local coordinates. + where (x, y) are the coordinates of the pointer location, in + surface-local coordinates. On surface.attach requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters @@ -1817,8 +1817,8 @@ <arg name="serial" type="uint" summary="serial of the enter event"/> <arg name="surface" type="object" interface="wl_surface" allow-null="true"/> - <arg name="hotspot_x" type="int" summary="x coordinate in surface local coordinates"/> - <arg name="hotspot_y" type="int" summary="y coordinate in surface local coordinates"/> + <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/> + <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/> </request> <event name="enter"> @@ -1833,8 +1833,8 @@ <arg name="serial" type="uint"/> <arg name="surface" type="object" interface="wl_surface"/> - <arg name="surface_x" type="fixed" summary="x coordinate in surface local coordinates"/> - <arg name="surface_y" type="fixed" summary="y coordinate in surface local coordinates"/> + <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/> + <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/> </event> <event name="leave"> @@ -1857,8 +1857,8 @@ </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="surface_x" type="fixed" summary="x coordinate in surface local coordinates"/> - <arg name="surface_y" type="fixed" summary="y coordinate in surface local coordinates"/> + <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/> + <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/> </event> <enum name="button_state"> @@ -2214,8 +2214,8 @@ <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> <arg name="surface" type="object" interface="wl_surface"/> <arg name="id" type="int" summary="the unique ID of this touch point"/> - <arg name="x" type="fixed" summary="x coordinate in surface local coordinates"/> - <arg name="y" type="fixed" summary="y coordinate in surface local coordinates"/> + <arg name="x" type="fixed" summary="surface-local x coordinate"/> + <arg name="y" type="fixed" summary="surface-local y coordinate"/> </event> <event name="up"> @@ -2235,8 +2235,8 @@ </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> <arg name="id" type="int" summary="the unique ID of this touch point"/> - <arg name="x" type="fixed" summary="x coordinate in surface local coordinates"/> - <arg name="y" type="fixed" summary="y coordinate in surface local coordinates"/> + <arg name="x" type="fixed" summary="surface-local x coordinate"/> + <arg name="y" type="fixed" summary="surface-local y coordinate"/> </event> <event name="frame"> From 519177cff7921006c3413bfa480d54aa45f4ddc1 Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Mon, 2 May 2016 09:49:33 +0100 Subject: [PATCH 0305/1152] client: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eric Engestrom <eric@engestrom.ch> Reviewed-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 7af806ce..03c087a6 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -581,7 +581,7 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned - * on success or NULL on errror with errno set accordingly. The newly + * on success or NULL on error with errno set accordingly. The newly * created proxy will inherit their version from their parent. * * \note This is intended to be used by language bindings and not in @@ -616,7 +616,7 @@ wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned - * on success or NULL on errror with errno set accordingly. The newly + * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * \note This is intended to be used by language bindings and not in @@ -711,7 +711,7 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned - * on success or NULL on errror with errno set accordingly. The newly + * on success or NULL on error with errno set accordingly. The newly * created proxy will inherit their version from their parent. * * \note This should not normally be used by non-generated code. @@ -749,7 +749,7 @@ wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned - * on success or NULL on errror with errno set accordingly. The newly + * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * \note This should not normally be used by non-generated code. From 8f4db349aaca8684774147cc4d5e2788633b5a0c Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Mon, 2 May 2016 09:49:34 +0100 Subject: [PATCH 0306/1152] server: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eric Engestrom <eric@engestrom.ch> Reviewed-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index ae9365f8..f745e624 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1308,7 +1308,7 @@ wl_display_add_socket_fd(struct wl_display *display, int sock_fd) * fails and returns -1. * * The length of socket path, i.e., the path set in XDG_RUNTIME_DIR and the - * socket name, must not exceed the maxium length of a Unix socket path. + * socket name, must not exceed the maximum length of a Unix socket path. * The function also fails if the user do not have write permission in the * XDG_RUNTIME_DIR path or if the socket name is already in use. * From 479945b4f1c34207ad785f844eca3e422af1c6dd Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Mon, 2 May 2016 09:49:35 +0100 Subject: [PATCH 0307/1152] util: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eric Engestrom <eric@engestrom.ch> Reviewed-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index cc1999d6..8da156c0 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -300,7 +300,7 @@ union wl_argument { * A dispatcher takes five arguments: The first is the dispatcher-specific * implementation data associated with the target object. The second is the * object on which the callback is being invoked (either wl_proxy or - * wl_resource). The third and fourth arguments are the opcode the wl_messsage + * wl_resource). The third and fourth arguments are the opcode the wl_message * structure corresponding to the callback being emitted. The final argument * is an array of arguments received from the other process via the wire * protocol. From 3c1aafd2a9157a884478bcd32263baad8d8b78fb Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Mon, 2 May 2016 09:49:36 +0100 Subject: [PATCH 0308/1152] doc: fix typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eric Engestrom <eric@engestrom.ch> Reviewed-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/Contributing | 10 +++++----- doc/publican/sources/Protocol.xml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/Contributing b/doc/Contributing index 65565dca..c790a071 100644 --- a/doc/Contributing +++ b/doc/Contributing @@ -22,13 +22,13 @@ The body of the commit message should describe what the patch changes and why, and also note any particular side effects. This shouldn't be empty on most of the cases. It shouldn't take a lot of effort to write a commit message for an obvious change, so an empty commit message -body is only acceptable if the questions "What?" and "Why" are already +body is only acceptable if the questions "What?" and "Why?" are already answered on the one-line summary. The lines of the commit message should have at most 76 characters, to cope with the way git log presents them. -See [2] for a recommend reading on writing commit messages. +See [2] for a recommended reading on writing commit messages. Your patches should also include a Signed-off-by line with your name and email address. If you're not the patch's original author, you should @@ -122,7 +122,7 @@ try to follow the rules below. - indent with tabs, and a tab is always 8 characters wide - opening braces are on the same line as the if statement; - no braces in an if-body with just one statement; -- if one of the branches of an if-else codition has braces, than the +- if one of the branches of an if-else condition has braces, then the other branch should also have braces; - there is always an empty line between variable declarations and the code; @@ -147,7 +147,7 @@ my_function(void) - lines should be less than 80 characters wide; - when breaking lines with functions calls, the parameters are aligned - with the opening parenthesis; + with the opening parentheses; - when assigning a variable with the result of a function call, if the line would be longer we break it around the equal '=' sign if it makes sense; @@ -166,7 +166,7 @@ Originally, X.org was covered under the MIT X11 license, but changed to the MIT Expat license. Similarly, Wayland was covered initially as MIT X11 licensed, but changed to the MIT Expat license, following in X.org's footsteps. Other than wording, the two licenses are substantially the -same, with the exeption of a no-advertising clause in X11 not included +same, with the exception of a no-advertising clause in X11 not included in Expat. New source code files should specify the MIT Expat license in their diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 481e1756..ba6b5f1e 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -199,7 +199,7 @@ Every interface is versioned and every protocol object implements a particular version of its interface. For global objects, the maximum version supported by the server is advertised with the global and the - actual verion of the created protocol object is determined by the + actual version of the created protocol object is determined by the version argument passed to wl_registry.bind(). For objects that are not globals, their version is inferred from the object that created them. From ee4e21c8a3c5a1b1b18cd1145364ddeec263965f Mon Sep 17 00:00:00 2001 From: Eric Engestrom <eric@engestrom.ch> Date: Mon, 2 May 2016 09:49:37 +0100 Subject: [PATCH 0309/1152] tests: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eric Engestrom <eric@engestrom.ch> Reviewed-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- tests/test-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 742b4f0b..4aa6667a 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -205,7 +205,7 @@ run_test(const struct test *t) t->run(); - /* turn off timeout (if any) after test completition */ + /* turn off timeout (if any) after test completion */ if (timeouts_enabled) alarm(0); From e21aeb5d1290de0ab67995bbd6341ef399a1f399 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Sat, 30 Apr 2016 07:35:50 -0500 Subject: [PATCH 0310/1152] protocol: Add summaries to event parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All event arg elements now have an appropriate summary attribute. This was conducted mostly in response to the undocumented parameter warnings generated during 'make check'. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 128 ++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 378879e4..1555677b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -70,9 +70,9 @@ own set of error codes. The message is a brief description of the error, for (debugging) convenience. </description> - <arg name="object_id" type="object"/> - <arg name="code" type="uint"/> - <arg name="message" type="string"/> + <arg name="object_id" type="object" summary="object where the error occurred"/> + <arg name="code" type="uint" summary="error code"/> + <arg name="message" type="string" summary="error description"/> </event> <enum name="error"> @@ -96,7 +96,7 @@ When the client receives this event, it will know that it can safely reuse the object ID. </description> - <arg name="id" type="uint" /> + <arg name="id" type="uint" summary="deleted object id"/> </event> </interface> @@ -141,9 +141,9 @@ the given name is now available, and it implements the given version of the given interface. </description> - <arg name="name" type="uint"/> - <arg name="interface" type="string"/> - <arg name="version" type="uint"/> + <arg name="name" type="uint" summary="numeric name of the global object"/> + <arg name="interface" type="string" summary="interface implemented by the object"/> + <arg name="version" type="uint" summary="interface version"/> </event> <event name="global_remove"> @@ -159,7 +159,7 @@ ignored until the client destroys it, to avoid races between the global going away and a client sending a request to it. </description> - <arg name="name" type="uint"/> + <arg name="name" type="uint" summary="numeric name of the global object"/> </event> </interface> @@ -367,7 +367,7 @@ can be used for buffers. Known formats include argb8888 and xrgb8888. </description> - <arg name="format" type="uint" enum="format"/> + <arg name="format" type="uint" enum="format" summary="buffer pixel format"/> </event> </interface> @@ -485,7 +485,7 @@ event per offered mime type. </description> - <arg name="mime_type" type="string"/> + <arg name="mime_type" type="string" summary="offered mime type"/> </event> <!-- Version 3 additions --> @@ -550,7 +550,7 @@ will be sent right after wl_data_device.enter, or anytime the source side changes its offered actions through wl_data_source.set_actions. </description> - <arg name="source_actions" type="uint"/> + <arg name="source_actions" type="uint" summary="actions offered by the data source"/> </event> <event name="action" since="3"> @@ -591,7 +591,7 @@ final wl_data_offer.set_actions and wl_data_offer.accept requests must happen before the call to wl_data_offer.finish. </description> - <arg name="dnd_action" type="uint"/> + <arg name="dnd_action" type="uint" summary="action selected by the compositor"/> </event> </interface> @@ -633,7 +633,7 @@ Used for feedback during drag-and-drop. </description> - <arg name="mime_type" type="string" allow-null="true"/> + <arg name="mime_type" type="string" allow-null="true" summary="mime type accepted by the target"/> </event> <event name="send"> @@ -643,8 +643,8 @@ close it. </description> - <arg name="mime_type" type="string"/> - <arg name="fd" type="fd"/> + <arg name="mime_type" type="string" summary="mime type for the data"/> + <arg name="fd" type="fd" summary="file descriptor for the data"/> </event> <event name="cancelled"> @@ -746,7 +746,7 @@ Clients can trigger cursor surface changes from this point, so they reflect the current action. </description> - <arg name="dnd_action" type="uint"/> + <arg name="dnd_action" type="uint" summary="action selected by the compositor"/> </event> </interface> @@ -821,7 +821,7 @@ mime types it offers. </description> - <arg name="id" type="new_id" interface="wl_data_offer"/> + <arg name="id" type="new_id" interface="wl_data_offer" summary="the new data_offer object"/> </event> <event name="enter"> @@ -832,11 +832,12 @@ coordinates. </description> - <arg name="serial" type="uint"/> - <arg name="surface" type="object" interface="wl_surface"/> - <arg name="x" type="fixed"/> - <arg name="y" type="fixed"/> - <arg name="id" type="object" interface="wl_data_offer" allow-null="true"/> + <arg name="serial" type="uint" summary="serial number of the enter event"/> + <arg name="surface" type="object" interface="wl_surface" summary="client surface entered"/> + <arg name="x" type="fixed" summary="surface-local x coordinate"/> + <arg name="y" type="fixed" summary="surface-local y coordinate"/> + <arg name="id" type="object" interface="wl_data_offer" allow-null="true" + summary="source data_offer object"/> </event> <event name="leave"> @@ -855,8 +856,8 @@ coordinates. </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="x" type="fixed"/> - <arg name="y" type="fixed"/> + <arg name="x" type="fixed" summary="surface-local x coordinate"/> + <arg name="y" type="fixed" summary="surface-local y coordinate"/> </event> <event name="drop"> @@ -891,7 +892,8 @@ destroy the previous selection data_offer, if any, upon receiving this event. </description> - <arg name="id" type="object" interface="wl_data_offer" allow-null="true"/> + <arg name="id" type="object" interface="wl_data_offer" allow-null="true" + summary="selection data_offer object"/> </event> <!-- Version 2 additions --> @@ -1230,7 +1232,7 @@ Ping a client to check if it is receiving events and sending requests. A client is expected to reply with a pong request. </description> - <arg name="serial" type="uint"/> + <arg name="serial" type="uint" summary="serial number of the ping"/> </event> <event name="configure"> @@ -1254,9 +1256,9 @@ in surface-local coordinates. </description> - <arg name="edges" type="uint" enum="resize"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> + <arg name="edges" type="uint" enum="resize" summary="how the surface was resized"/> + <arg name="width" type="int" summary="new width of the surface"/> + <arg name="height" type="int" summary="new height of the surface"/> </event> <event name="popup_done"> @@ -1532,7 +1534,7 @@ Note that a surface may be overlapping with zero or more outputs. </description> - <arg name="output" type="object" interface="wl_output"/> + <arg name="output" type="object" interface="wl_output" summary="output entered by the surface"/> </event> <event name="leave"> @@ -1541,7 +1543,7 @@ results in it no longer having any part of it within the scanout region of an output. </description> - <arg name="output" type="object" interface="wl_output"/> + <arg name="output" type="object" interface="wl_output" summary="output left by the surface"/> </event> <!-- Version 2 additions --> @@ -1700,7 +1702,7 @@ The above behavior also applies to wl_keyboard and wl_touch with the keyboard and touch capabilities, respectively. </description> - <arg name="capabilities" type="uint" enum="capability"/> + <arg name="capabilities" type="uint" enum="capability" summary="capabilities of the seat"/> </event> <request name="get_pointer"> @@ -1750,7 +1752,7 @@ identify which physical devices the seat represents. Based on the seat configuration used by the compositor. </description> - <arg name="name" type="string"/> + <arg name="name" type="string" summary="seat identifier"/> </event> <!-- Version 5 additions --> @@ -1831,8 +1833,8 @@ an appropriate pointer image with the set_cursor request. </description> - <arg name="serial" type="uint"/> - <arg name="surface" type="object" interface="wl_surface"/> + <arg name="serial" type="uint" summary="serial number of the enter event"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface entered by the pointer"/> <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/> <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/> </event> @@ -1845,8 +1847,8 @@ The leave notification is sent before the enter notification for the new focus. </description> - <arg name="serial" type="uint"/> - <arg name="surface" type="object" interface="wl_surface"/> + <arg name="serial" type="uint" summary="serial number of the leave event"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface left by the pointer"/> </event> <event name="motion"> @@ -1880,10 +1882,10 @@ granularity, with an undefined base. </description> - <arg name="serial" type="uint"/> + <arg name="serial" type="uint" summary="serial number of the button event"/> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="button" type="uint"/> - <arg name="state" type="uint" enum="button_state"/> + <arg name="button" type="uint" summary="button that produced the event"/> + <arg name="state" type="uint" enum="button_state" summary="physical state of the button"/> </event> <enum name="axis"> @@ -1915,8 +1917,8 @@ </description> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="axis" type="uint" enum="axis"/> - <arg name="value" type="fixed"/> + <arg name="axis" type="uint" enum="axis" summary="axis type"/> + <arg name="value" type="fixed" summary="length of vector in surface-local coordinate space"/> </event> <!-- Version 3 additions --> @@ -2019,7 +2021,7 @@ The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. </description> - <arg name="axis_source" type="uint" enum="axis_source"/> + <arg name="axis_source" type="uint" enum="axis_source" summary="source of the axis event"/> </event> <event name="axis_stop" since="5"> @@ -2072,8 +2074,8 @@ The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. </description> - <arg name="axis" type="uint" enum="axis" /> - <arg name="discrete" type="int"/> + <arg name="axis" type="uint" enum="axis" summary="axis type"/> + <arg name="discrete" type="int" summary="number of steps"/> </event> </interface> @@ -2099,9 +2101,9 @@ This event provides a file descriptor to the client which can be memory-mapped to provide a keyboard mapping description. </description> - <arg name="format" type="uint" enum="keymap_format"/> - <arg name="fd" type="fd"/> - <arg name="size" type="uint"/> + <arg name="format" type="uint" enum="keymap_format" summary="keymap format"/> + <arg name="fd" type="fd" summary="keymap file descriptor"/> + <arg name="size" type="uint" summary="keymap size, in bytes"/> </event> <event name="enter"> @@ -2109,8 +2111,8 @@ Notification that this seat's keyboard focus is on a certain surface. </description> - <arg name="serial" type="uint"/> - <arg name="surface" type="object" interface="wl_surface"/> + <arg name="serial" type="uint" summary="serial number of the enter event"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface gaining keyboard focus"/> <arg name="keys" type="array" summary="the currently pressed keys"/> </event> @@ -2122,8 +2124,8 @@ The leave notification is sent before the enter notification for the new focus. </description> - <arg name="serial" type="uint"/> - <arg name="surface" type="object" interface="wl_surface"/> + <arg name="serial" type="uint" summary="serial number of the leave event"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface that lost keyboard focus"/> </event> <enum name="key_state"> @@ -2141,10 +2143,10 @@ granularity, with an undefined base. </description> - <arg name="serial" type="uint"/> + <arg name="serial" type="uint" summary="serial number of the key event"/> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="key" type="uint"/> - <arg name="state" type="uint" enum="key_state"/> + <arg name="key" type="uint" summary="key that produced the event"/> + <arg name="state" type="uint" enum="key_state" summary="physical state of the key"/> </event> <event name="modifiers"> @@ -2153,11 +2155,11 @@ changed, and it should update its local state. </description> - <arg name="serial" type="uint"/> - <arg name="mods_depressed" type="uint"/> - <arg name="mods_latched" type="uint"/> - <arg name="mods_locked" type="uint"/> - <arg name="group" type="uint"/> + <arg name="serial" type="uint" summary="serial number of the modifiers event"/> + <arg name="mods_depressed" type="uint" summary="depressed modifiers"/> + <arg name="mods_latched" type="uint" summary="latched modifiers"/> + <arg name="mods_locked" type="uint" summary="locked modifiers"/> + <arg name="group" type="uint" summary="keyboard layout"/> </event> <!-- Version 3 additions --> @@ -2210,9 +2212,9 @@ this ID. The ID ceases to be valid after a touch up event and may be reused in the future. </description> - <arg name="serial" type="uint"/> + <arg name="serial" type="uint" summary="serial number of the touch down event"/> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> - <arg name="surface" type="object" interface="wl_surface"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface touched"/> <arg name="id" type="int" summary="the unique ID of this touch point"/> <arg name="x" type="fixed" summary="surface-local x coordinate"/> <arg name="y" type="fixed" summary="surface-local y coordinate"/> @@ -2224,7 +2226,7 @@ this touch point and the touch point's ID is released and may be reused in a future touch down event. </description> - <arg name="serial" type="uint"/> + <arg name="serial" type="uint" summary="serial number of the touch up event"/> <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> <arg name="id" type="int" summary="the unique ID of this touch point"/> </event> From 7ccf35d43209ca4c4283cd3a3746f8126d4c64c1 Mon Sep 17 00:00:00 2001 From: Auke Booij <auke@tulcod.com> Date: Sat, 5 Dec 2015 12:39:12 +0000 Subject: [PATCH 0311/1152] protocol: add support for cross-interface enum attributes The enum attribute, for which scanner support was introduced in 1771299, can be used to link message arguments to <enum>s. However, some arguments refer to <enum>s in a different <interface>. This adds scanner support for referring to an <enum> in a different <interface> using dot notation. It also sets the attributes in this style in the wayland XML protocol (wl_shm_pool::create_buffer::format to wl_shm::format, and wl_surface::set_buffer_transform::transform to wl_output::transform), and updates the documentation XSL so that this new style is supported. Changes since v2: - add object:: prefix for all enumerations in the documentation - fix whitespace in scanner.c - minor code fixup to return early and avoid casts in scanner.c Changes since v1: - several implementation bugs fixed Signed-off-by: Auke Booij <auke@tulcod.com> Reviewed-by: Nils Christopher Brause <nilschrbrause@googlemail.com> Reviewed-by: Bill Spitzak <spitzak@gmail.com> [Pekka: rebased across cde251a124d41977b447098cc530fcad2834a45f] [Pekka: wrap lines and space fixes in scanner.c] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- doc/publican/protocol-to-docbook.xsl | 19 ++++++-- protocol/wayland.xml | 4 +- src/scanner.c | 69 +++++++++++++++++++++------- 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 5344442d..210e0dbb 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -152,9 +152,22 @@ <term><xsl:value-of select="@name"/></term> <listitem> <simpara> - <link linkend="protocol-spec-{../../@name}-enum-{@enum}"> - <xsl:value-of select="../../@name"/>::<xsl:value-of select="@enum"/> - </link> + <xsl:choose> + <xsl:when test="contains(@enum, '.')"> + <link linkend="protocol-spec-{substring-before(@enum, '.')}-enum-{substring-after(@enum, '.')}"> + <xsl:value-of select="substring-before(@enum, '.')"/> + <xsl:text>::</xsl:text> + <xsl:value-of select="substring-after(@enum, '.')"/> + </link> + </xsl:when> + <xsl:otherwise> + <link linkend="protocol-spec-{../../@name}-enum-{@enum}"> + <xsl:value-of select="../../@name"/> + <xsl:text>::</xsl:text> + <xsl:value-of select="@enum"/> + </link> + </xsl:otherwise> + </xsl:choose> (<xsl:value-of select="@type"/>) <xsl:if test="@summary" > - <xsl:value-of select="@summary"/> diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 1555677b..92e3f433 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -229,7 +229,7 @@ <arg name="width" type="int"/> <arg name="height" type="int"/> <arg name="stride" type="int"/> - <arg name="format" type="uint"/> + <arg name="format" type="uint" enum="wl_shm.format"/> </request> <request name="destroy" type="destructor"> @@ -1580,7 +1580,7 @@ wl_output.transform enum the invalid_transform protocol error is raised. </description> - <arg name="transform" type="int"/> + <arg name="transform" type="int" enum="wl_output.transform"/> </request> <!-- Version 3 additions --> diff --git a/src/scanner.c b/src/scanner.c index 52c07a6c..1317a06a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -752,8 +752,8 @@ start_element(void *data, const char *element_name, const char **atts) enumeration->bitfield = true; else fail(&ctx->loc, - "invalid value (%s) for bitfield attribute (only true/false are accepted)", - bitfield); + "invalid value (%s) for bitfield attribute (only true/false are accepted)", + bitfield); wl_list_insert(ctx->interface->enumeration_list.prev, &enumeration->link); @@ -790,32 +790,68 @@ start_element(void *data, const char *element_name, const char **atts) } } +static struct enumeration * +find_enumeration(struct protocol *protocol, + struct interface *interface, + char *enum_attribute) +{ + struct interface *i; + struct enumeration *e; + char *enum_name; + uint idx = 0, j; + + for (j = 0; j + 1 < strlen(enum_attribute); j++) { + if (enum_attribute[j] == '.') { + idx = j; + } + } + + if (idx > 0) { + enum_name = enum_attribute + idx + 1; + + wl_list_for_each(i, &protocol->interface_list, link) + if (strncmp(i->name, enum_attribute, idx) == 0) + wl_list_for_each(e, &i->enumeration_list, link) + if (strcmp(e->name, enum_name) == 0) + return e; + } else if (interface) { + enum_name = enum_attribute; + + wl_list_for_each(e, &interface->enumeration_list, link) + if (strcmp(e->name, enum_name) == 0) + return e; + } + + return NULL; +} + static void -verify_arguments(struct parse_context *ctx, struct wl_list *messages, struct wl_list *enumerations) +verify_arguments(struct parse_context *ctx, + struct interface *interface, + struct wl_list *messages, + struct wl_list *enumerations) { struct message *m; wl_list_for_each(m, messages, link) { struct arg *a; wl_list_for_each(a, &m->arg_list, link) { - struct enumeration *e, *f; + struct enumeration *e; if (!a->enumeration_name) continue; - f = NULL; - wl_list_for_each(e, enumerations, link) { - if(strcmp(e->name, a->enumeration_name) == 0) - f = e; - } - if (f == NULL) + e = find_enumeration(ctx->protocol, interface, + a->enumeration_name); + + if (e == NULL) fail(&ctx->loc, "could not find enumeration %s", a->enumeration_name); switch (a->type) { case INT: - if (f->bitfield) + if (e->bitfield) fail(&ctx->loc, "bitfield-style enum must only be referenced by uint"); break; @@ -853,12 +889,13 @@ end_element(void *data, const XML_Char *name) ctx->enumeration->name); } ctx->enumeration = NULL; - } else if (strcmp(name, "interface") == 0) { - struct interface *i = ctx->interface; - - verify_arguments(ctx, &i->request_list, &i->enumeration_list); - verify_arguments(ctx, &i->event_list, &i->enumeration_list); + } else if (strcmp(name, "protocol") == 0) { + struct interface *i; + wl_list_for_each(i, &ctx->protocol->interface_list, link) { + verify_arguments(ctx, i, &i->request_list, &i->enumeration_list); + verify_arguments(ctx, i, &i->event_list, &i->enumeration_list); + } } } From 08bda63ac4aa483c046fcbf8dd62a1103ffe9683 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 3 May 2016 17:56:22 -0700 Subject: [PATCH 0312/1152] configure.ac: bump to version 1.10.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bbe62f7d..a42dfc05 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [10]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 721c91c54a705fc3e971e94d8afe46993af953f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armin=20Krezovi=C4=87?= <krezovic.armin@gmail.com> Date: Thu, 5 May 2016 17:27:57 +0200 Subject: [PATCH 0313/1152] scanner: Add version argument to wayland-scanner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a command line argument to print wayland-scanner version. It also makes wayland-scanner emit a comment with wayland library version to every file it generates. v2: separate variable definitions into their own lines and remove old style "version" argument Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> Tested-by: Yong Bakos <ybakos@humanoriented.com> Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/scanner.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 1317a06a..037ebdb4 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -26,6 +26,7 @@ */ #include "config.h" +#include "wayland-version.h" #include <stdbool.h> #include <stdio.h> @@ -64,12 +65,21 @@ usage(int ret) "headers, server headers, or protocol marshalling code.\n\n"); fprintf(stderr, "options:\n"); fprintf(stderr, " -h, --help display this help and exit.\n" + " -v, --version print the wayland library version that\n" + " the scanner was built against.\n" " -c, --include-core-only include the core version of the headers,\n" " that is e.g. wayland-client-core.h instead\n" " of wayland-client.h.\n"); exit(ret); } +static int +scanner_version(int ret) +{ + fprintf(stderr, "wayland-scanner %s\n", WAYLAND_VERSION); + exit(ret); +} + static bool is_dtd_valid(FILE *input, const char *filename) { @@ -1457,6 +1467,8 @@ emit_header(struct protocol *protocol, enum side side) const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; char **p, *prev; + printf("/* Generated by wayland-scanner %s */\n\n", WAYLAND_VERSION); + printf("#ifndef %s_%s_PROTOCOL_H\n" "#define %s_%s_PROTOCOL_H\n" "\n" @@ -1658,6 +1670,8 @@ emit_code(struct protocol *protocol) struct wl_array types; char **p, *prev; + printf("/* Generated by wayland-scanner %s */\n\n", WAYLAND_VERSION); + if (protocol->copyright) format_text_to_comment(protocol->copyright, true); @@ -1735,7 +1749,9 @@ int main(int argc, char *argv[]) char *input_filename = NULL; int len; void *buf; - bool help = false, core_headers = false; + bool help = false; + bool core_headers = false; + bool version = false; bool fail = false; int opt; enum { @@ -1746,12 +1762,13 @@ int main(int argc, char *argv[]) static const struct option options[] = { { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, { "include-core-only", no_argument, NULL, 'c' }, { 0, 0, NULL, 0 } }; while (1) { - opt = getopt_long(argc, argv, "hc", options, NULL); + opt = getopt_long(argc, argv, "hvc", options, NULL); if (opt == -1) break; @@ -1760,6 +1777,9 @@ int main(int argc, char *argv[]) case 'h': help = true; break; + case 'v': + version = true; + break; case 'c': core_headers = true; break; @@ -1774,6 +1794,8 @@ int main(int argc, char *argv[]) if (help) usage(EXIT_SUCCESS); + else if (version) + scanner_version(EXIT_SUCCESS); else if ((argc != 1 && argc != 3) || fail) usage(EXIT_FAILURE); else if (strcmp(argv[0], "help") == 0) From c6d204fdbcffec742416d3971ef1efd3b6eb575a Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Sat, 7 May 2016 18:14:11 -0500 Subject: [PATCH 0314/1152] protocol: Remove double line break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All vertical whitespace should manifest as a single blank line, never two. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> --- protocol/wayland.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 92e3f433..700ef037 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -407,7 +407,6 @@ </event> </interface> - <interface name="wl_data_offer" version="3"> <description summary="offer to transfer data"> A wl_data_offer represents a piece of data offered for transfer From e5b12aa827a777dc6455b9a87909a222157c256f Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Sun, 8 May 2016 14:42:28 -0500 Subject: [PATCH 0315/1152] doc: Formalize file comment in wayland-client.h, wayland-server.h Publican was generating a subtle error during a build: Error: no ID for constraint linkend: Server-wayland-server-core_8h. This was caused by doxygen applying the doc comment at the top of wayland-server.h as the documentation for struct wl_object. As such, the generated documentation for wl_object was also very incorrect. Make the file doc comments in wayland-client.h and wayland-server.h real doxygen file doc comments with the \file command, add a \brief, make the inclusion warning a \warning, correct the language of the comment in wayland-server.h, and remove one unnecessary line break. This squelches the publican error, removes the bad wl_object documentation, and makes the comment appear in the generated html documentation. References: d74a9c079b1aeb44f69b4132dc2c38362e21f281 Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-client.h | 7 +++++-- src/wayland-server.h | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/wayland-client.h b/src/wayland-client.h index 38565357..9f70fa3f 100644 --- a/src/wayland-client.h +++ b/src/wayland-client.h @@ -23,8 +23,11 @@ * SOFTWARE. */ - -/** Use of this header file is discouraged. Prefer including +/** \file + * + * \brief Include the client API and protocol C API. + * + * \warning Use of this header file is discouraged. Prefer including * wayland-client-core.h instead, which does not include the * client protocol header and as such only defines the library * API. diff --git a/src/wayland-server.h b/src/wayland-server.h index b6d0e2bc..31247031 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -23,10 +23,13 @@ * SOFTWARE. */ - -/** Use of this header file is discouraged. Prefer including +/** \file + * + * \brief Include the server API, deprecations and protocol C API. + * + * \warning Use of this header file is discouraged. Prefer including * wayland-server-core.h instead, which does not include the - * client protocol header and as such only defines the library + * server protocol header and as such only defines the library * API, excluding the deprecated API below. */ From 385906beae3a7605629fd3a582f1be9254d7345b Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Sun, 8 May 2016 08:44:08 -0500 Subject: [PATCH 0316/1152] connection: Move wl_interface_equal to util Move the wl_interface_equal prototype to the top of wayland-private, where it is not buried in the middle of map, connection and closure functions. Move the implementation out of connection and into util. This is a utility function, not specific to connections, and has call sites within connection, wayland-client and wayland-server. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/connection.c | 13 ------------- src/wayland-private.h | 8 ++++---- src/wayland-util.c | 13 +++++++++++++ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/connection.c b/src/connection.c index 747229e5..c3293a9f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -797,19 +797,6 @@ wl_connection_demarshal(struct wl_connection *connection, return NULL; } -int -wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) -{ - /* In most cases the pointer equality test is sufficient. - * However, in some cases, depending on how things are split - * across shared objects, we can end up with multiple - * instances of the interface metadata constants. So if the - * pointers match, the interfaces are equal, if they don't - * match we have to compare the interface names. */ - - return a == b || strcmp(a->name, b->name) == 0; -} - int wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) { diff --git a/src/wayland-private.h b/src/wayland-private.h index 994bc453..a9a07a8e 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -55,6 +55,10 @@ struct wl_object { extern struct wl_object global_zombie_object; #define WL_ZOMBIE_OBJECT ((void*)&global_zombie_object) +int +wl_interface_equal(const struct wl_interface *iface1, + const struct wl_interface *iface2); + /* Flags for wl_map_insert_new and wl_map_insert_at. Flags can be queried with * wl_map_lookup_flags. The current implementation has room for 1 bit worth of * flags. If more flags are ever added, the implementation of wl_map will have @@ -103,10 +107,6 @@ struct wl_connection; struct wl_closure; struct wl_proxy; -int -wl_interface_equal(const struct wl_interface *iface1, - const struct wl_interface *iface2); - struct wl_connection * wl_connection_create(int fd); diff --git a/src/wayland-util.c b/src/wayland-util.c index 748476a2..5bfb7e14 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -35,6 +35,19 @@ struct wl_object global_zombie_object; +int +wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) +{ + /* In most cases the pointer equality test is sufficient. + * However, in some cases, depending on how things are split + * across shared objects, we can end up with multiple + * instances of the interface metadata constants. So if the + * pointers match, the interfaces are equal, if they don't + * match we have to compare the interface names. + */ + return a == b || strcmp(a->name, b->name) == 0; +} + WL_EXPORT void wl_list_init(struct wl_list *list) { From f86fbe1a115fe2bf0da066e66ed73349cc2c378c Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Sat, 7 May 2016 09:11:30 -0500 Subject: [PATCH 0317/1152] private: Remove unnecessary forward declarations Declarations for wl_connection and wl_closure are not needed here. wl_closure already has a complete definition. Removing these forward declarations results in a clean, warning-free compile. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> [Updated to apply to trunk] Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-private.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index a9a07a8e..045109b0 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -103,10 +103,6 @@ wl_map_lookup_flags(struct wl_map *map, uint32_t i); void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data); -struct wl_connection; -struct wl_closure; -struct wl_proxy; - struct wl_connection * wl_connection_create(int fd); From f19b569ec2cf2f8dbaf00d62e2f6b131f29aeec4 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 17 May 2016 22:07:48 -0700 Subject: [PATCH 0318/1152] configure.ac: bump to version 1.10.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a42dfc05..ca6e8c59 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [10]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 9ca9f8e4b27f51a4d8b1b0823a93f15cf76540aa Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 19 May 2016 10:27:29 -0600 Subject: [PATCH 0319/1152] tests: Check for client/server-core.h inclusion The purpose of wayland-*-protocol-core.h is to mimc the wayland-*-protocol.h generated by scanner --include-core-only. The only difference being what wayland-*-protocol.h should include. Add an include check in the headers-protocol-core-test, to be sure that a wayland-*-protocol.h generated with the --include-core-only option properly includes wayland-*-core.h. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- tests/headers-protocol-core-test.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/headers-protocol-core-test.c b/tests/headers-protocol-core-test.c index aabcb0b3..5c2baf36 100644 --- a/tests/headers-protocol-core-test.c +++ b/tests/headers-protocol-core-test.c @@ -26,6 +26,13 @@ #include "wayland-client-protocol-core.h" #include "wayland-server-protocol-core.h" +#ifndef WAYLAND_CLIENT_CORE_H +#error including wayland-client-protocol-core.h did not include wayland-client-core.h! +#endif +#ifndef WAYLAND_SERVER_CORE_H +#error including wayland-server-protocol-core.h did not include wayland-server-core.h! +#endif + #ifdef WAYLAND_CLIENT_H #error including wayland-client-protocol-core.h included wayland-client.h! #endif From cc11b493426c46e86aee0bcd7c92ca9e9e23030d Mon Sep 17 00:00:00 2001 From: Marek Chalupa <mchqwerty@gmail.com> Date: Fri, 13 May 2016 15:01:18 +0200 Subject: [PATCH 0320/1152] display-test: move a misplaced comment we split a function while refactoring in c643781 and now the comment makes no sense Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- tests/display-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index f9f81600..17956db8 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -211,8 +211,6 @@ find_client_info(struct display *d, struct wl_client *client) { struct client_info *ci; - /* find the right client_info struct and save the - * resource as its data, so that we can use it later */ wl_list_for_each(ci, &d->clients, link) { if (ci->wl_client == client) return ci; @@ -235,6 +233,8 @@ bind_seat(struct wl_client *client, void *data, res = wl_resource_create(client, &wl_seat_interface, vers, id); assert(res); + /* save the resource as client's info data, + * so that we can use it later */ ci->data = res; } From 97fef4821327b5daecbee9c6cb0fc1de93181cff Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 19 May 2016 20:31:16 -0600 Subject: [PATCH 0321/1152] scanner: Remove unused forward decs from client protocol wayland-client-protocol.h had forward declarations for wl_client and wl_resource, yet nothing on the client side references these types. Add a 'side' condition to only generate these forward declarations in the server protocol header. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: <pekka.paalanen@collabora.co.uk> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/scanner.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 037ebdb4..5f06e8e2 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1477,13 +1477,13 @@ emit_header(struct protocol *protocol, enum side side) "#include \"%s\"\n\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" - "#endif\n" - "\n" - "struct wl_client;\n" - "struct wl_resource;\n\n", + "#endif\n\n", protocol->uppercase_name, s, protocol->uppercase_name, s, get_include_name(protocol->core_headers, side)); + if (side == SERVER) + printf("struct wl_client;\n" + "struct wl_resource;\n\n"); emit_mainpage_blurb(protocol, side); From 62d67fe8fa217994f1d82dcb3203bb651e1c011f Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 24 May 2016 12:29:59 -0700 Subject: [PATCH 0322/1152] configure.ac: bump to version 1.10.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ca6e8c59..7dba928f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [10]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 47163797f810373c81b6e13b7a8a245eb9877785 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 31 May 2016 17:11:20 -0700 Subject: [PATCH 0323/1152] configure.ac: bump to version 1.11.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7dba928f..cf965293 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [10]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [11]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 98d94b5c1d1cc21f5c963cdebc1cd535c6ae5b4f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Date: Wed, 1 Jun 2016 11:08:02 +0300 Subject: [PATCH 0324/1152] configure.ac: bump version to 1.11.90 for open development As announced in 1.11.0 release notes, master is open again. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cf965293..9af3574f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [11]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 3e58aa1e0621f9183188bc79c51e0a3eca932465 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 12 May 2016 15:52:37 -0500 Subject: [PATCH 0325/1152] doc: Unpublish wl_display_get_additional_shm_formats The Wayland docbook and the doxygen html docs had been presenting wl_display_get_additional_shm_formats as part of the public API, but the prototype for this function is in wayland-private.h. Add a \private annotation to the doc comment, preventing doxygen from publishing this function as public. Add logic to the publican xsl to only transform elements with a "prot" attribute value of "public". Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- doc/publican/doxygen-to-publican.xsl | 2 +- src/wayland-server.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl index 7c3b5075..e13dcd76 100644 --- a/doc/publican/doxygen-to-publican.xsl +++ b/doc/publican/doxygen-to-publican.xsl @@ -101,7 +101,7 @@ <!-- methods --> <xsl:template match="memberdef" > - <xsl:if test="@kind = 'function' and @static = 'no' or + <xsl:if test="@kind = 'function' and @static = 'no' and @prot = 'public' or @kind !='function' and normalize-space(briefdescription) != ''"> <varlistentry id="{$which}-{@id}"> <term> diff --git a/src/wayland-server.c b/src/wayland-server.c index f745e624..ad82bc24 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1470,6 +1470,8 @@ wl_display_add_shm_format(struct wl_display *display, uint32_t format) * * \sa wl_display_add_shm_format() * + * \private + * * \memberof wl_display */ struct wl_array * From d29b9233058004eef321f847a588b94eb86c1d36 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 12 May 2016 15:52:38 -0500 Subject: [PATCH 0326/1152] doc: Unpublish wl_log* and wl_abort The public documentation included descriptions of wl_log_stderr_handler, wl_log_func_t wl_log_handler, wl_log and wl_abort. These are not accessible via the public API. Move the doxygen \endcond command to wrap these definitions, removing them from publication. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 5bfb7e14..407d1f05 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -379,8 +379,6 @@ wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) for_each_helper(&map->server_entries, func, data); } -/** \endcond */ - static void wl_log_stderr_handler(const char *fmt, va_list arg) { @@ -410,3 +408,5 @@ wl_abort(const char *fmt, ...) abort(); } + +/** \endcond */ From a1bce0ead5a7d46f719e1f890fd7e4d0fa5d7d55 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 12 May 2016 15:52:39 -0500 Subject: [PATCH 0327/1152] doc: Unpublish global_zombie_object and wl_interface_equal Both global_zombie_object and wl_interface_equal are private, yet were part of public documentation despite not being part of the public API. Move these two definitions to the top of an existing doxygen \cond block, which removes them from the public documentation. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-util.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 407d1f05..7467366d 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -33,21 +33,6 @@ #include "wayland-util.h" #include "wayland-private.h" -struct wl_object global_zombie_object; - -int -wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) -{ - /* In most cases the pointer equality test is sufficient. - * However, in some cases, depending on how things are split - * across shared objects, we can end up with multiple - * instances of the interface metadata constants. So if the - * pointers match, the interfaces are equal, if they don't - * match we have to compare the interface names. - */ - return a == b || strcmp(a->name, b->name) == 0; -} - WL_EXPORT void wl_list_init(struct wl_list *list) { @@ -167,6 +152,21 @@ wl_array_copy(struct wl_array *array, struct wl_array *source) /** \cond */ +struct wl_object global_zombie_object; + +int +wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) +{ + /* In most cases the pointer equality test is sufficient. + * However, in some cases, depending on how things are split + * across shared objects, we can end up with multiple + * instances of the interface metadata constants. So if the + * pointers match, the interfaces are equal, if they don't + * match we have to compare the interface names. + */ + return a == b || strcmp(a->name, b->name) == 0; +} + union map_entry { uintptr_t next; void *data; From 972f1a2cf78a257a50edae58826e43835155adeb Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Mon, 16 May 2016 12:05:39 -0600 Subject: [PATCH 0328/1152] event-loop: Make transitive include explicit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The explicit inclusion of wayland-server.h hides the real dependency, which is wayland-server-core.h. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> --- src/event-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index ea27b695..11a9bf2f 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -37,7 +37,7 @@ #include <sys/timerfd.h> #include <unistd.h> #include "wayland-private.h" -#include "wayland-server.h" +#include "wayland-server-core.h" #include "wayland-os.h" struct wl_event_loop { From d588efcbc8153c01b61c7056a0171ac5cddd5103 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Tue, 17 May 2016 21:02:01 -0600 Subject: [PATCH 0329/1152] wayland-server: Clarify included header dependencies wayland-server.c directly depends on wayland-util.h, and will include wayland-server-protocol.h via wayland-server.h. Explicitly include wayland-util.h, making this dependency clear. Remove the redundant inclusion of wayland-server-protocol.h. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index ad82bc24..19aa2e8f 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -43,9 +43,9 @@ #include <sys/file.h> #include <sys/stat.h> +#include "wayland-util.h" #include "wayland-private.h" #include "wayland-server.h" -#include "wayland-server-protocol.h" #include "wayland-os.h" /* This is the size of the char array in struct sock_addr_un. From 36aeaf037b11a8c5cd421cd013cf634838f5653c Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Mon, 6 Jun 2016 10:58:56 -0700 Subject: [PATCH 0330/1152] scanner: Fix reported executable name to 'wayland-scanner' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'wayland-scanner -v' (correctly) reports the program as named "wayland-scanner", but 'wayland-scanner -h' was inconsistent, referring to it as './scanner'. Also refactor this and other references to the program name to use a common #define, PROGRAM_NAME. Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> Tested-by: Yong Bakos <ybakos@humanoriented.com> --- src/scanner.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 5f06e8e2..d5442c17 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -42,6 +42,8 @@ #if HAVE_LIBXML #include <libxml/parser.h> +#define PROGRAM_NAME "wayland-scanner" + /* Embedded wayland.dtd file, see dtddata.S */ extern char DTD_DATA_begin; extern int DTD_DATA_len; @@ -57,8 +59,8 @@ enum side { static int usage(int ret) { - fprintf(stderr, "usage: ./scanner [OPTION] [client-header|server-header|code]" - " [input_file output_file]\n"); + fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|code]" + " [input_file output_file]\n", PROGRAM_NAME); fprintf(stderr, "\n"); fprintf(stderr, "Converts XML protocol descriptions supplied on " "stdin or input file to client\n" @@ -76,7 +78,7 @@ usage(int ret) static int scanner_version(int ret) { - fprintf(stderr, "wayland-scanner %s\n", WAYLAND_VERSION); + fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION); exit(ret); } @@ -236,7 +238,7 @@ static void * fail_on_null(void *p) { if (p == NULL) { - fprintf(stderr, "wayland-scanner: out of memory\n"); + fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME); exit(EXIT_FAILURE); } @@ -1467,7 +1469,7 @@ emit_header(struct protocol *protocol, enum side side) const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; char **p, *prev; - printf("/* Generated by wayland-scanner %s */\n\n", WAYLAND_VERSION); + printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); printf("#ifndef %s_%s_PROTOCOL_H\n" "#define %s_%s_PROTOCOL_H\n" @@ -1670,7 +1672,7 @@ emit_code(struct protocol *protocol) struct wl_array types; char **p, *prev; - printf("/* Generated by wayland-scanner %s */\n\n", WAYLAND_VERSION); + printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); if (protocol->copyright) format_text_to_comment(protocol->copyright, true); From 9000c0f20eb0e2b26b26cb85e27c9cd2ef0e312f Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Fri, 20 May 2016 22:18:36 -0600 Subject: [PATCH 0331/1152] wayland-shm: Include wayland-util.h wayland-shm.c uses WL_EXPORT and wl_array, which are defined in wayland-util.h. Include wayland-util.h explicitly, rather than transitively through wayland-server.h. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Sam Spilsbury <smspillaz@gmail.com> --- src/wayland-shm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 5efbd70d..20bb8c82 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -40,6 +40,7 @@ #include <signal.h> #include <pthread.h> +#include "wayland-util.h" #include "wayland-private.h" #include "wayland-server.h" From fe31d2f9affae349728c6a328a9da77411160a49 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Fri, 20 May 2016 22:23:58 -0600 Subject: [PATCH 0332/1152] event-loop: Include wayland-util.h event-loop.c uses WL_EXPORT and wl_list, which are defined in wayland-util.h. Include wayland-util.h explicitly, rather than transitively through wayland-server-core.h. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Sam Spilsbury <smspillaz@gmail.com> --- src/event-loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/event-loop.c b/src/event-loop.c index 11a9bf2f..7f1c7e5e 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -36,6 +36,7 @@ #include <sys/signalfd.h> #include <sys/timerfd.h> #include <unistd.h> +#include "wayland-util.h" #include "wayland-private.h" #include "wayland-server-core.h" #include "wayland-os.h" From e5bd4122e95e71e0b0535ae5381cdf2650b0e2a7 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Mon, 23 May 2016 17:06:09 -0600 Subject: [PATCH 0333/1152] client-core: Add missing line breaks Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-client-core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index b1d65155..dfd3e18f 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -150,10 +150,12 @@ wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, const struct wl_interface *interface, uint32_t version, ...); + struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface); + struct wl_proxy * wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, From 826b16641ade360ee3d68f96eac168e08b56daae Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Mon, 23 May 2016 17:59:33 -0600 Subject: [PATCH 0334/1152] server, server-core: Minimize fwd decs, use macro, and format wayland-server.h: Adjust line breaks between prototypes. wayland-server-core.h: Adjust line breaks between prototypes. Adjust space between splats and identifiers. Remove unconventional linebreak before first parameter. Add line breaks after return types. Remove unnecessary forward declarations, and: - move 'struct wl_client' declaration close to the dependent typedef - tastefully move 'wl_shm_buffer_get' to leverage the return type Replace explicit __attribute__ with WL_PRINTF macro. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-server-core.h | 51 ++++++++++++++++++++++----------------- src/wayland-server.h | 2 +- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index fa7f3945..408c1377 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -42,8 +42,6 @@ enum { WL_EVENT_ERROR = 0x08 }; -struct wl_event_loop; -struct wl_event_source; typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data); typedef int (*wl_event_loop_timer_func_t)(void *data); typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data); @@ -85,7 +83,6 @@ wl_event_source_remove(struct wl_event_source *source); void wl_event_source_check(struct wl_event_source *source); - int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout); @@ -100,20 +97,16 @@ wl_event_loop_add_idle(struct wl_event_loop *loop, int wl_event_loop_get_fd(struct wl_event_loop *loop); -struct wl_client; -struct wl_display; struct wl_listener; -struct wl_resource; -struct wl_global; + typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data); void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, - struct wl_listener * listener); + struct wl_listener *listener); struct wl_listener * -wl_event_loop_get_destroy_listener( - struct wl_event_loop *loop, +wl_event_loop_get_destroy_listener(struct wl_event_loop *loop, wl_notify_func_t notify); struct wl_display * @@ -143,6 +136,8 @@ wl_display_run(struct wl_display *display); void wl_display_flush_clients(struct wl_display *display); +struct wl_client; + typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, uint32_t version, uint32_t id); @@ -360,16 +355,17 @@ void wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...); -void wl_resource_queue_event_array(struct wl_resource *resource, - uint32_t opcode, union wl_argument *args); +void +wl_resource_queue_event_array(struct wl_resource *resource, + uint32_t opcode, union wl_argument *args); /* msg is a printf format string, variable args are its args. */ void wl_resource_post_error(struct wl_resource *resource, - uint32_t code, const char *msg, ...) - __attribute__ ((format (printf, 3, 4))); + uint32_t code, const char *msg, ...) WL_PRINTF(3, 4); -void wl_resource_post_no_memory(struct wl_resource *resource); +void +wl_resource_post_no_memory(struct wl_resource *resource); struct wl_display * wl_client_get_display(struct wl_client *client); @@ -378,11 +374,13 @@ struct wl_resource * wl_resource_create(struct wl_client *client, const struct wl_interface *interface, int version, uint32_t id); + void wl_resource_set_implementation(struct wl_resource *resource, const void *implementation, void *data, wl_resource_destroy_func_t destroy); + void wl_resource_set_dispatcher(struct wl_resource *resource, wl_dispatcher_func_t dispatcher, @@ -392,25 +390,35 @@ wl_resource_set_dispatcher(struct wl_resource *resource, void wl_resource_destroy(struct wl_resource *resource); + uint32_t wl_resource_get_id(struct wl_resource *resource); + struct wl_list * wl_resource_get_link(struct wl_resource *resource); + struct wl_resource * wl_resource_from_link(struct wl_list *resource); + struct wl_resource * wl_resource_find_for_client(struct wl_list *list, struct wl_client *client); + struct wl_client * wl_resource_get_client(struct wl_resource *resource); + void wl_resource_set_user_data(struct wl_resource *resource, void *data); + void * wl_resource_get_user_data(struct wl_resource *resource); + int wl_resource_get_version(struct wl_resource *resource); + void wl_resource_set_destructor(struct wl_resource *resource, wl_resource_destroy_func_t destroy); + int wl_resource_instance_of(struct wl_resource *resource, const struct wl_interface *interface, @@ -418,7 +426,8 @@ wl_resource_instance_of(struct wl_resource *resource, void wl_resource_add_destroy_listener(struct wl_resource *resource, - struct wl_listener * listener); + struct wl_listener *listener); + struct wl_listener * wl_resource_get_destroy_listener(struct wl_resource *resource, wl_notify_func_t notify); @@ -436,8 +445,8 @@ wl_resource_get_destroy_listener(struct wl_resource *resource, resource = tmp, \ tmp = wl_resource_from_link(wl_resource_get_link(resource)->next)) -struct wl_shm_pool; -struct wl_shm_buffer; +struct wl_shm_buffer * +wl_shm_buffer_get(struct wl_resource *resource); void wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer); @@ -445,9 +454,6 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer); void wl_shm_buffer_end_access(struct wl_shm_buffer *buffer); -struct wl_shm_buffer * -wl_shm_buffer_get(struct wl_resource *resource); - void * wl_shm_buffer_get_data(struct wl_shm_buffer *buffer); @@ -480,7 +486,8 @@ wl_shm_buffer_create(struct wl_client *client, uint32_t id, int32_t width, int32_t height, int32_t stride, uint32_t format) WL_DEPRECATED; -void wl_log_set_handler_server(wl_log_func_t handler); +void +wl_log_set_handler_server(wl_log_func_t handler); #ifdef __cplusplus } diff --git a/src/wayland-server.h b/src/wayland-server.h index 31247031..a6e7951a 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -65,7 +65,6 @@ struct wl_buffer { uint32_t busy_count; } WL_DEPRECATED; - uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource) WL_DEPRECATED; @@ -75,6 +74,7 @@ wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, uint32_t id, void *data) WL_DEPRECATED; + struct wl_resource * wl_client_new_object(struct wl_client *client, const struct wl_interface *interface, From 0cc2eb9ef0e5a8c6fc21916421e6db81d6460b02 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Tue, 24 May 2016 13:55:12 -0600 Subject: [PATCH 0335/1152] scanner: Replace #define tab with space wayland-client-protocol.h and wayland-server-protocol.h use a tab between the identifier and token of generated #defines for request/event opcodes and versions. While this sometimes enables vertical alignment, it more frequently doesn't, and leads to awkward spacing. Replace the tab with a space, for consistency and readability. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Tested-by: Quentin Glidic <sardemff7+git@sardemff7.net> --- src/scanner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index d5442c17..705473b5 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -964,7 +964,7 @@ emit_opcodes(struct wl_list *message_list, struct interface *interface) opcode = 0; wl_list_for_each(m, message_list, link) - printf("#define %s_%s\t%d\n", + printf("#define %s_%s %d\n", interface->uppercase_name, m->uppercase_name, opcode++); printf("\n"); @@ -977,7 +977,7 @@ emit_opcode_versions(struct wl_list *message_list, struct interface *interface) wl_list_for_each(m, message_list, link) { printf("/**\n * @ingroup iface_%s\n */\n", interface->name); - printf("#define %s_%s_SINCE_VERSION\t%d\n", + printf("#define %s_%s_SINCE_VERSION %d\n", interface->uppercase_name, m->uppercase_name, m->since); } From e1f2ba2b37e79220baec4c1c229228734a344595 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Tue, 24 May 2016 17:10:17 -0600 Subject: [PATCH 0336/1152] server-core, event-loop: Fix parameter alignment. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/event-loop.c | 8 ++++---- src/wayland-server-core.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index 7f1c7e5e..32216a7c 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -228,7 +228,7 @@ struct wl_event_source_signal { static int wl_event_source_signal_dispatch(struct wl_event_source *source, - struct epoll_event *ep) + struct epoll_event *ep) { struct wl_event_source_signal *signal_source = (struct wl_event_source_signal *) source; @@ -250,9 +250,9 @@ struct wl_event_source_interface signal_source_interface = { WL_EXPORT struct wl_event_source * wl_event_loop_add_signal(struct wl_event_loop *loop, - int signal_number, - wl_event_loop_signal_func_t func, - void *data) + int signal_number, + wl_event_loop_signal_func_t func, + void *data) { struct wl_event_source_signal *source; sigset_t mask; diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 408c1377..ad1292f1 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -69,9 +69,9 @@ wl_event_loop_add_timer(struct wl_event_loop *loop, struct wl_event_source * wl_event_loop_add_signal(struct wl_event_loop *loop, - int signal_number, - wl_event_loop_signal_func_t func, - void *data); + int signal_number, + wl_event_loop_signal_func_t func, + void *data); int wl_event_source_timer_update(struct wl_event_source *source, From d6d7dab487a8acd02c1fae45eea78954411c51b8 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Tue, 7 Jun 2016 10:19:39 -0500 Subject: [PATCH 0337/1152] scanner: Move PROGRAM_NAME define PROGRAM_NAME was defined within the if block of HAVE_LIBXML, causing a compilation failure when libxml is not present. Move the define of PROGRAM_NAME out of the if block. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> --- src/scanner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 705473b5..4708cae0 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -42,8 +42,6 @@ #if HAVE_LIBXML #include <libxml/parser.h> -#define PROGRAM_NAME "wayland-scanner" - /* Embedded wayland.dtd file, see dtddata.S */ extern char DTD_DATA_begin; extern int DTD_DATA_len; @@ -51,6 +49,8 @@ extern int DTD_DATA_len; #include "wayland-util.h" +#define PROGRAM_NAME "wayland-scanner" + enum side { CLIENT, SERVER, From 1cda73f3f85514ef18f180d350e1e390ff388f10 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Fri, 8 Jul 2016 19:00:20 -0700 Subject: [PATCH 0338/1152] tests: Require base 10 for the string specifying the number of open fd's The third arg to strtol() specifies the base to assume for the number. When 0 is passed, as is currently done in wayland-client.c, hexadecimal and octal numbers are permitted and automatically detected and converted. exec-fd-leak-checker's single argument is the count of file descriptors it should expect to be open. We should expect this to be specified only as a decimal number, there's no reason why one would want to use octal or hexadecimal for that. Suggested by Yong Bakos. Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> --- tests/exec-fd-leak-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/exec-fd-leak-checker.c b/tests/exec-fd-leak-checker.c index 0c69da3a..5f3b3958 100644 --- a/tests/exec-fd-leak-checker.c +++ b/tests/exec-fd-leak-checker.c @@ -37,7 +37,7 @@ parse_count(const char *str, int *value) long v; errno = 0; - v = strtol(str, &end, 0); + v = strtol(str, &end, 10); if ((errno == ERANGE && (v == LONG_MAX || v == LONG_MIN)) || (errno != 0 && v == 0) || (end == str) || From c88ec7e2914a5b85fd878e4ee96f31aa26be05c8 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Fri, 8 Jul 2016 16:51:16 -0700 Subject: [PATCH 0339/1152] scanner: Improve documentation for strtouint() Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> --- src/scanner.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 4708cae0..6e2c3a3b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -576,8 +576,17 @@ free_interface(struct interface *interface) free(interface); } -/* convert string to unsigned integer, - * in the case of error, return -1 */ +/* Convert string to unsigned integer + * + * Parses a non-negative base-10 number from the given string. If the + * specified string is blank, contains non-numerical characters, is out + * of range, or results in a negative number, -1 is returned to indicate + * an error. + * + * Upon error, this routine does not modify or set errno. + * + * \returns -1 on error, or a non-negative integer on success + */ static int strtouint(const char *str) { From 6750b47d9e0d3074d2e56aa36c476493f533d696 Mon Sep 17 00:00:00 2001 From: Khem Raj <raj.khem@gmail.com> Date: Fri, 15 Jul 2016 16:23:48 -0700 Subject: [PATCH 0340/1152] scanner: Use uint32_t instead of uint uint32_t is C99 defined stdint type Signed-off-by: Khem Raj <raj.khem@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 6e2c3a3b..ebae4ccc 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -819,7 +819,7 @@ find_enumeration(struct protocol *protocol, struct interface *i; struct enumeration *e; char *enum_name; - uint idx = 0, j; + uint32_t idx = 0, j; for (j = 0; j + 1 < strlen(enum_attribute); j++) { if (enum_attribute[j] == '.') { From 2b1c1b2d66945c5cb237a7264759b6dbdf42b02a Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Mon, 18 Jul 2016 12:42:25 -0500 Subject: [PATCH 0341/1152] (multiple): Include stdint.h Some headers and source files have been using types such as uint32_t without explicitly including stdint.h. Explicitly include stdint.h where appropriate. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> --- cursor/cursor-data.h | 2 ++ cursor/wayland-cursor.c | 1 + src/event-loop.c | 1 + src/scanner.c | 1 + src/wayland-client-core.h | 1 + src/wayland-private.h | 1 + src/wayland-server.h | 1 + src/wayland-shm.c | 1 + tests/connection-test.c | 1 + tests/display-test.c | 1 + tests/event-loop-test.c | 1 + tests/map-test.c | 1 + tests/os-wrappers-test.c | 1 + tests/queue-test.c | 1 + tests/resources-test.c | 1 + tests/test-compositor.c | 1 + tests/test-compositor.h | 1 + 17 files changed, 18 insertions(+) diff --git a/cursor/cursor-data.h b/cursor/cursor-data.h index 0d03cd53..dd7a80af 100644 --- a/cursor/cursor-data.h +++ b/cursor/cursor-data.h @@ -25,6 +25,8 @@ * Author: Keith Packard, SuSE, Inc. */ +#include <stdint.h> + static uint32_t cursor_data[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 18abe87a..d40c5c8e 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -29,6 +29,7 @@ #include "wayland-client.h" #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <unistd.h> #include <sys/mman.h> diff --git a/src/event-loop.c b/src/event-loop.c index 32216a7c..6130d2af 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -28,6 +28,7 @@ #include <errno.h> #include <signal.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <fcntl.h> #include <sys/socket.h> diff --git a/src/scanner.c b/src/scanner.c index ebae4ccc..d501ba75 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -31,6 +31,7 @@ #include <stdbool.h> #include <stdio.h> #include <stdarg.h> +#include <stdint.h> #include <string.h> #include <errno.h> #include <ctype.h> diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index dfd3e18f..03e781b5 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -26,6 +26,7 @@ #ifndef WAYLAND_CLIENT_CORE_H #define WAYLAND_CLIENT_CORE_H +#include <stdint.h> #include "wayland-util.h" #include "wayland-version.h" diff --git a/src/wayland-private.h b/src/wayland-private.h index 045109b0..adfbe016 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -30,6 +30,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <stdint.h> #define WL_HIDE_DEPRECATED 1 diff --git a/src/wayland-server.h b/src/wayland-server.h index a6e7951a..f11fb4d0 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -36,6 +36,7 @@ #ifndef WAYLAND_SERVER_H #define WAYLAND_SERVER_H +#include <stdint.h> #include "wayland-server-core.h" #ifdef __cplusplus diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 20bb8c82..7fea364c 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -33,6 +33,7 @@ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> diff --git a/tests/connection-test.c b/tests/connection-test.c index 5d97fd98..3e34f779 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -27,6 +27,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> #include <string.h> #include <assert.h> #include <sys/socket.h> diff --git a/tests/display-test.c b/tests/display-test.c index 17956db8..f4800ce9 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -28,6 +28,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> #include <string.h> #include <assert.h> #include <sys/socket.h> diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index ae5ff945..33566b41 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -25,6 +25,7 @@ */ #include <stdlib.h> +#include <stdint.h> #include <assert.h> #include <unistd.h> #include <signal.h> diff --git a/tests/map-test.c b/tests/map-test.c index d2590488..8ecc1aa5 100644 --- a/tests/map-test.c +++ b/tests/map-test.c @@ -25,6 +25,7 @@ #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <assert.h> #include "wayland-private.h" #include "test-runner.h" diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index b636b622..102622c3 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -27,6 +27,7 @@ #define _GNU_SOURCE #include <stdlib.h> +#include <stdint.h> #include <assert.h> #include <sys/types.h> #include <sys/socket.h> diff --git a/tests/queue-test.c b/tests/queue-test.c index 932bc555..86a36025 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -24,6 +24,7 @@ */ #include <stdlib.h> +#include <stdint.h> #include <stdio.h> #include <stdbool.h> #include <unistd.h> diff --git a/tests/resources-test.c b/tests/resources-test.c index 337f9f9f..59d8beb7 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -26,6 +26,7 @@ #include <assert.h> #include <sys/socket.h> #include <unistd.h> +#include <stdint.h> #include "wayland-server.h" #include "test-runner.h" diff --git a/tests/test-compositor.c b/tests/test-compositor.c index b01e8afe..0631f614 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -28,6 +28,7 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <stdint.h> #include <unistd.h> #include <sys/time.h> #include <sys/socket.h> diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 526e9123..876d0c09 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -23,6 +23,7 @@ * SOFTWARE. */ +#include <stdint.h> #include <unistd.h> #include "wayland-server.h" From 993df5792820758427c79ab0c2ab6621f3d85ce6 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Mon, 18 Jul 2016 12:46:00 -0500 Subject: [PATCH 0342/1152] display-test: Remove redundant stdbool include display-test.c includes stdbool.h twice. Remove the redundant include. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- tests/display-test.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/display-test.c b/tests/display-test.c index f4800ce9..0c4df169 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -38,7 +38,6 @@ #include <sys/stat.h> #include <pthread.h> #include <poll.h> -#include <stdbool.h> #include "wayland-private.h" #include "wayland-server.h" From bad9dc5186e46ab92e1680d1f0ea4a4d4f0f7211 Mon Sep 17 00:00:00 2001 From: Quentin Glidic <sardemff7+git@sardemff7.net> Date: Tue, 5 Jul 2016 20:41:49 +0200 Subject: [PATCH 0343/1152] protocol: Add release (destructor) request to wl_output Outputs come and go, and this is needed to clean up wl_resources on the server side. All protocol objects need a way to be destroyed. Cc: Neil Roberts <neil@linux.intel.com> Cc: Jason Ekstrand <jason@jlekstrand.net> Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> [Pekka: added commit message] --- protocol/wayland.xml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 700ef037..0830afcd 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2264,7 +2264,7 @@ </request> </interface> - <interface name="wl_output" version="2"> + <interface name="wl_output" version="3"> <description summary="compositor output region"> An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an @@ -2369,6 +2369,8 @@ <arg name="refresh" type="int" summary="vertical refresh rate in mHz"/> </event> + <!-- Version 2 additions --> + <event name="done" since="2"> <description summary="sent all information about output"> This event is sent after all other properties have been @@ -2402,6 +2404,15 @@ </description> <arg name="factor" type="int" summary="scaling factor of output"/> </event> + + <!-- Version 3 additions --> + + <request name="release" type="destructor" since="3"> + <description summary="release the output object"> + Using this request a client can tell the server that it is not going to + use the output object anymore. + </description> + </request> </interface> <interface name="wl_region" version="1"> From 5636cb2f056d813b464c451754908e17de838e3a Mon Sep 17 00:00:00 2001 From: Quentin Glidic <sardemff7+git@sardemff7.net> Date: Tue, 5 Jul 2016 20:41:50 +0200 Subject: [PATCH 0344/1152] scanner: Generate all SINCE_VERSION macros for everyone Practical example: a client supporting version 2 of wl_output will wait for the wl_output.done event before starting wl_output-related operations. However, if the server only supports version 1, no event will ever come, and it must fallback to use the wl_output.geometry event alone. Without this macro, it cannot check for that in a nice way. This patch introduces the same #defines in both server and client headers. We rely on both being generated from the same XML file and https://gcc.gnu.org/onlinedocs/cpp/Undefining-and-Redefining-Macros.html to not cause compiler errors or warning due to redefinitions. We also assume that no-one uses the same name in the same interface for both a request and an event. If this patch does cause grief due to identical redefinitions, the contingency plan is to change the generator to produce #ifndef/#define/#endif instead of just #define. Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> [Pekka: add paragraphs to commit message.] --- src/scanner.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index d501ba75..c9272759 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1554,10 +1554,12 @@ emit_header(struct protocol *protocol, enum side side) emit_structs(&i->request_list, i, side); emit_opcodes(&i->event_list, i); emit_opcode_versions(&i->event_list, i); + emit_opcode_versions(&i->request_list, i); emit_event_wrappers(&i->event_list, i); } else { emit_structs(&i->event_list, i, side); emit_opcodes(&i->request_list, i); + emit_opcode_versions(&i->event_list, i); emit_opcode_versions(&i->request_list, i); emit_stubs(&i->request_list, i); } From be48da6a42b399252959ef782132fdfdf62c6905 Mon Sep 17 00:00:00 2001 From: Sungjae Park <nicesj@nicesj.com> Date: Tue, 9 Aug 2016 12:46:51 +0200 Subject: [PATCH 0345/1152] server: add listener API for new clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using display object, Emit a signal if a new client is created. In the server-side, we can get the destroy event of a client, But there is no way to get the created event of it. Of course, we can get the client object from the global registry binding callbacks. But it can be called several times with same client object. And even if A client creates display object, (so there is a connection), The server could not know that. There could be more use-cases not only for this. Giulio: a test is added for the new functionality Signed-off-by: Sung-jae Park <nicesj@nicesj.com> Signed-off-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- Makefile.am | 5 +- src/wayland-server-core.h | 4 ++ src/wayland-server.c | 25 ++++++++ tests/compositor-introspection-test.c | 87 +++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/compositor-introspection-test.c diff --git a/Makefile.am b/Makefile.am index 49e25a66..e684a871 100644 --- a/Makefile.am +++ b/Makefile.am @@ -160,7 +160,8 @@ TESTS = \ signal-test \ resources-test \ message-test \ - headers-test + headers-test \ + compositor-introspection-test if ENABLE_CPP_TEST TESTS += cpp-compile-test @@ -217,6 +218,8 @@ resources_test_SOURCES = tests/resources-test.c resources_test_LDADD = libtest-runner.la message_test_SOURCES = tests/message-test.c message_test_LDADD = libtest-runner.la +compositor_introspection_test_SOURCES = tests/compositor-introspection-test.c +compositor_introspection_test_LDADD = libtest-runner.la headers_test_SOURCES = tests/headers-test.c \ tests/headers-protocol-test.c \ tests/headers-protocol-core-test.c diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index ad1292f1..43e76fb1 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -151,6 +151,10 @@ void wl_display_add_destroy_listener(struct wl_display *display, struct wl_listener *listener); +void +wl_display_add_client_created_listener(struct wl_display *display, + struct wl_listener *listener); + struct wl_listener * wl_display_get_destroy_listener(struct wl_display *display, wl_notify_func_t notify); diff --git a/src/wayland-server.c b/src/wayland-server.c index 19aa2e8f..b44ec9c1 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -96,6 +96,7 @@ struct wl_display { struct wl_list client_list; struct wl_signal destroy_signal; + struct wl_signal create_client_signal; struct wl_array additional_shm_formats; }; @@ -406,6 +407,9 @@ bind_display(struct wl_client *client, struct wl_display *display); * wl_display_connect_to_fd() on the client side or used with the * WAYLAND_SOCKET environment variable on the client side. * + * Listeners added with wl_display_add_client_created_listener() will + * be notified by this function after the client is fully constructed. + * * On failure this function sets errno accordingly and returns NULL. * * \memberof wl_display @@ -448,6 +452,8 @@ wl_client_create(struct wl_display *display, int fd) wl_list_insert(display->client_list.prev, &client->link); + wl_signal_emit(&display->create_client_signal, client); + return client; err_map: @@ -864,6 +870,7 @@ wl_display_create(void) wl_list_init(&display->registry_resource_list); wl_signal_init(&display->destroy_signal); + wl_signal_init(&display->create_client_signal); display->id = 1; display->serial = 0; @@ -1353,6 +1360,24 @@ wl_display_add_destroy_listener(struct wl_display *display, wl_signal_add(&display->destroy_signal, listener); } +/** Registers a listener for the client connection signal. + * When a new client object is created, \a listener will be notified, carrying + * a pointer to the new wl_client object. + * + * \ref wl_client_create + * \ref wl_display + * \ref wl_listener + * + * \param display The display object + * \param listener Signal handler object + */ +WL_EXPORT void +wl_display_add_client_created_listener(struct wl_display *display, + struct wl_listener *listener) +{ + wl_signal_add(&display->create_client_signal, listener); +} + WL_EXPORT struct wl_listener * wl_display_get_destroy_listener(struct wl_display *display, wl_notify_func_t notify) diff --git a/tests/compositor-introspection-test.c b/tests/compositor-introspection-test.c new file mode 100644 index 00000000..5d2085d4 --- /dev/null +++ b/tests/compositor-introspection-test.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/un.h> +#include <unistd.h> + +#include "wayland-client.h" +#include "wayland-server.h" +#include "test-runner.h" + +/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ +static const char * +require_xdg_runtime_dir(void) +{ + char *val = getenv("XDG_RUNTIME_DIR"); + assert(val && "set $XDG_RUNTIME_DIR to run this test"); + + return val; +} + +struct compositor { + struct wl_display *display; + struct wl_listener listener; + struct wl_client *client; +}; + +static void +client_created(struct wl_listener *listener, void *data) +{ + struct compositor *c = wl_container_of(listener, c, listener); + c->client = data; +} + +TEST(new_client_connect) +{ + const char *socket; + struct compositor compositor = { 0 }; + struct { + struct wl_display *display; + } client; + + require_xdg_runtime_dir(); + + compositor.display = wl_display_create(); + socket = wl_display_add_socket_auto(compositor.display); + + compositor.listener.notify = client_created; + wl_display_add_client_created_listener(compositor.display, &compositor.listener); + + client.display = wl_display_connect(socket); + + wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); + + assert(compositor.client != NULL); + + wl_display_disconnect(client.display); + + wl_client_destroy(compositor.client); + wl_display_destroy(compositor.display); +} From 68abfa6732672ab3534102de55edaa10343f4d1b Mon Sep 17 00:00:00 2001 From: Giulio Camuffo <giuliocamuffo@gmail.com> Date: Tue, 9 Aug 2016 12:46:52 +0200 Subject: [PATCH 0346/1152] Add API to retrieve the interface name of a wl_resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> --- src/wayland-server-core.h | 2 ++ src/wayland-server.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 43e76fb1..c0d25e9e 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -427,6 +427,8 @@ int wl_resource_instance_of(struct wl_resource *resource, const struct wl_interface *interface, const void *implementation); +const char * +wl_resource_get_class(struct wl_resource *resource); void wl_resource_add_destroy_listener(struct wl_resource *resource, diff --git a/src/wayland-server.c b/src/wayland-server.c index b44ec9c1..e2212e2e 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -690,6 +690,18 @@ wl_resource_get_destroy_listener(struct wl_resource *resource, return wl_signal_get(&resource->destroy_signal, notify); } +/** Retrieve the interface name (class) of a resource object. + * + * \param resource The resource object + * + * \memberof wl_resource + */ +WL_EXPORT const char * +wl_resource_get_class(struct wl_resource *resource) +{ + return resource->object.interface->name; +} + WL_EXPORT void wl_client_add_destroy_listener(struct wl_client *client, struct wl_listener *listener) From 596024f728b0a1292ee69a80dd72a85167870936 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo <giuliocamuffo@gmail.com> Date: Tue, 9 Aug 2016 12:46:53 +0200 Subject: [PATCH 0347/1152] Add API to get the list of connected clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch chooses the wl_list_for_each-style of iterating over the clients, instead of using an iterator function, because i think it is easier to use. Signed-off-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-server-core.h | 14 +++++++ src/wayland-server.c | 54 +++++++++++++++++++++++++++ tests/compositor-introspection-test.c | 22 +++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index c0d25e9e..69c09dc2 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -171,6 +171,20 @@ wl_global_destroy(struct wl_global *global); struct wl_client * wl_client_create(struct wl_display *display, int fd); +struct wl_list * +wl_display_get_client_list(struct wl_display *display); + +struct wl_list * +wl_client_get_link(struct wl_client *client); + +struct wl_client * +wl_client_from_link(struct wl_list *link); + +#define wl_client_for_each(client, list) \ + for (client = wl_client_from_link((list)->next); \ + wl_client_get_link(client) != (list); \ + client = wl_client_from_link(wl_client_get_link(client)->next)) + void wl_client_destroy(struct wl_client *client); diff --git a/src/wayland-server.c b/src/wayland-server.c index e2212e2e..2dd9a4a4 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1517,6 +1517,60 @@ wl_display_get_additional_shm_formats(struct wl_display *display) return &display->additional_shm_formats; } +/** Get the list of currently connected clients + * + * \param display The display object + * + * This function returns a pointer to the list of clients currently + * connected to the display. You can iterate on the list by using + * the \a wl_client_for_each macro. + * The returned value is valid for the lifetime of the \a display. + * You must not modify the returned list, but only access it. + * + * \sa wl_client_for_each() + * \sa wl_client_get_link() + * \sa wl_client_from_link() + * + * \memberof wl_display + */ +WL_EXPORT struct wl_list * +wl_display_get_client_list(struct wl_display *display) +{ + return &display->client_list; +} + +/** Get the link by which a client is inserted in the client list + * + * \param client The client object + * + * \sa wl_client_for_each() + * \sa wl_display_get_client_list() + * \sa wl_client_from_link() + * + * \memberof wl_client + */ +WL_EXPORT struct wl_list * +wl_client_get_link(struct wl_client *client) +{ + return &client->link; +} + +/** Get a wl_client by its link + * + * \param link The link of a wl_client + * + * \sa wl_client_for_each() + * \sa wl_display_get_client_list() + * \sa wl_client_get_link() + * + * \memberof wl_client + */ +WL_EXPORT struct wl_client * +wl_client_from_link(struct wl_list *link) +{ + return container_of(link, struct wl_client, link); +} + /** \cond */ /* Deprecated functions below. */ uint32_t diff --git a/tests/compositor-introspection-test.c b/tests/compositor-introspection-test.c index 5d2085d4..50ff1ddb 100644 --- a/tests/compositor-introspection-test.c +++ b/tests/compositor-introspection-test.c @@ -58,6 +58,26 @@ client_created(struct wl_listener *listener, void *data) c->client = data; } +static void +check_client_list(struct compositor *compositor) +{ + struct wl_list *client_list; + struct wl_client *client, *client_it; + int num_clients = 0; + + client_list = wl_display_get_client_list(compositor->display); + wl_client_for_each(client_it, client_list) { + num_clients++; + client = client_it; + } + assert(num_clients == 1); + /* 'client_it' is not valid here, so we took a copy of the client in the loop. + * We could also do this assert in the loop directly, but in case it fails it is + * easier to understand the problem when we know that the previous assert passed, + * so that there is only one client but the wrong one. */ + assert(compositor->client == client); +} + TEST(new_client_connect) { const char *socket; @@ -80,6 +100,8 @@ TEST(new_client_connect) assert(compositor.client != NULL); + check_client_list(&compositor); + wl_display_disconnect(client.display); wl_client_destroy(compositor.client); From c55c1d787cb542de5ffee702c7ca9bcd27b56bef Mon Sep 17 00:00:00 2001 From: Giulio Camuffo <giuliocamuffo@gmail.com> Date: Thu, 11 Aug 2016 17:23:09 +0200 Subject: [PATCH 0348/1152] Add a resource creation signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change allows to add a resource creation listener to a wl_client, which will be notified when a new resource is created for that client. The alternative would be to have a per wl_display listener, but i think that resources are really client specific objects, so it makes sense to use the wl_client as the context. Signed-off-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> [Pekka: added wl_list_remove() in TEST(new_resource).] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-server-core.h | 4 ++ src/wayland-server.c | 33 +++++++++++ tests/compositor-introspection-test.c | 83 +++++++++++++++++++++++---- 3 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 69c09dc2..bb0a9894 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -212,6 +212,10 @@ wl_client_get_object(struct wl_client *client, uint32_t id); void wl_client_post_no_memory(struct wl_client *client); +void +wl_client_add_resource_created_listener(struct wl_client *client, + struct wl_listener *listener); + /** \class wl_listener * * \brief A single listener for Wayland signals diff --git a/src/wayland-server.c b/src/wayland-server.c index 2dd9a4a4..a396410c 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -81,6 +81,7 @@ struct wl_client { struct wl_signal destroy_signal; struct ucred ucred; int error; + struct wl_signal resource_created_signal; }; struct wl_display { @@ -424,6 +425,7 @@ wl_client_create(struct wl_display *display, int fd) if (client == NULL) return NULL; + wl_signal_init(&client->resource_created_signal); client->display = display; client->source = wl_event_loop_add_fd(display->loop, fd, WL_EVENT_READABLE, @@ -729,6 +731,7 @@ wl_client_destroy(struct wl_client *client) wl_event_source_remove(client->source); close(wl_connection_destroy(client->connection)); wl_list_remove(&client->link); + wl_list_remove(&client->resource_created_signal.listener_list); free(client); } @@ -1420,6 +1423,18 @@ wl_resource_set_dispatcher(struct wl_resource *resource, resource->destroy = destroy; } +/** Create a new resource object + * + * \param client The client owner of the new resource. + * \param interface The interface of the new resource. + * \param version The version of the new resource. + * \param id The id of the new resource. If 0, an available id will be used. + * + * Listeners added with \a wl_client_add_resource_created_listener will be + * notified at the end of this function. + * + * \memberof wl_resource + */ WL_EXPORT struct wl_resource * wl_resource_create(struct wl_client *client, const struct wl_interface *interface, @@ -1454,6 +1469,7 @@ wl_resource_create(struct wl_client *client, return NULL; } + wl_signal_emit(&client->resource_created_signal, resource); return resource; } @@ -1571,6 +1587,23 @@ wl_client_from_link(struct wl_list *link) return container_of(link, struct wl_client, link); } +/** Add a listener for the client's resource creation signal + * + * \param client The client object + * \param listener The listener to be added + * + * When a new resource is created for this client the listener + * will be notified, carrying the new resource as the data argument. + * + * \memberof wl_client + */ +WL_EXPORT void +wl_client_add_resource_created_listener(struct wl_client *client, + struct wl_listener *listener) +{ + wl_signal_add(&client->resource_created_signal, listener); +} + /** \cond */ /* Deprecated functions below. */ uint32_t diff --git a/tests/compositor-introspection-test.c b/tests/compositor-introspection-test.c index 50ff1ddb..83194ce2 100644 --- a/tests/compositor-introspection-test.c +++ b/tests/compositor-introspection-test.c @@ -78,6 +78,29 @@ check_client_list(struct compositor *compositor) assert(compositor->client == client); } +static const char * +setup_compositor(struct compositor *compositor) +{ + const char *socket; + + require_xdg_runtime_dir(); + + compositor->display = wl_display_create(); + socket = wl_display_add_socket_auto(compositor->display); + + compositor->listener.notify = client_created; + wl_display_add_client_created_listener(compositor->display, &compositor->listener); + + return socket; +} + +static void +cleanup_compositor(struct compositor *compositor) +{ + wl_client_destroy(compositor->client); + wl_display_destroy(compositor->display); +} + TEST(new_client_connect) { const char *socket; @@ -86,13 +109,7 @@ TEST(new_client_connect) struct wl_display *display; } client; - require_xdg_runtime_dir(); - - compositor.display = wl_display_create(); - socket = wl_display_add_socket_auto(compositor.display); - - compositor.listener.notify = client_created; - wl_display_add_client_created_listener(compositor.display, &compositor.listener); + socket = setup_compositor(&compositor); client.display = wl_display_connect(socket); @@ -102,8 +119,54 @@ TEST(new_client_connect) check_client_list(&compositor); - wl_display_disconnect(client.display); - wl_client_destroy(compositor.client); - wl_display_destroy(compositor.display); + + wl_display_disconnect(client.display); + cleanup_compositor(&compositor); +} + +struct resource_listener { + struct wl_listener listener; + int count; +}; + +static void +resource_created(struct wl_listener *listener, void *data) +{ + struct resource_listener *l; + l = wl_container_of(listener, l, listener); + l->count++; +} + +TEST(new_resource) +{ + const char *socket; + struct compositor compositor = { 0 }; + struct { + struct wl_display *display; + struct wl_callback *cb; + } client; + struct resource_listener resource_listener; + + socket = setup_compositor(&compositor); + client.display = wl_display_connect(socket); + wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); + + resource_listener.count = 0; + resource_listener.listener.notify = resource_created; + wl_client_add_resource_created_listener(compositor.client, + &resource_listener.listener); + + client.cb = wl_display_sync(client.display); + wl_display_flush(client.display); + wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); + + assert(resource_listener.count == 1); + + wl_callback_destroy(client.cb); + wl_display_disconnect(client.display); + cleanup_compositor(&compositor); + + /* This is defined to be safe also after client destruction */ + wl_list_remove(&resource_listener.listener.link); } From 2f617250d27ec3258071077997934c43948c384b Mon Sep 17 00:00:00 2001 From: Giulio Camuffo <giuliocamuffo@gmail.com> Date: Thu, 11 Aug 2016 17:23:10 +0200 Subject: [PATCH 0349/1152] Add API to retrieve and iterate over the resources list of a client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To complement on the new resource created signal, this allows to iterate over the existing resources of a client. Signed-off-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> [Pekka: added empty lines, init ret in for_each_helper()] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- src/wayland-private.h | 3 ++- src/wayland-server-core.h | 9 +++++++ src/wayland-server.c | 50 ++++++++++++++++++++++++++++++++++++++- src/wayland-util.c | 19 +++++++++++---- src/wayland-util.h | 11 +++++++++ 5 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index adfbe016..ac712d93 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -75,7 +75,8 @@ struct wl_map { uint32_t free_list; }; -typedef void (*wl_iterator_func_t)(void *element, void *data); +typedef enum wl_iterator_result (*wl_iterator_func_t)(void *element, + void *data); void wl_map_init(struct wl_map *map, uint32_t side); diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index bb0a9894..56e8d802 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -216,6 +216,15 @@ void wl_client_add_resource_created_listener(struct wl_client *client, struct wl_listener *listener); +typedef enum wl_iterator_result (*wl_client_for_each_resource_iterator_func_t)( + struct wl_resource *resource, + void *user_data); + +void +wl_client_for_each_resource(struct wl_client *client, + wl_client_for_each_resource_iterator_func_t iterator, + void *user_data); + /** \class wl_listener * * \brief A single listener for Wayland signals diff --git a/src/wayland-server.c b/src/wayland-server.c index a396410c..dd648ac2 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -565,7 +565,7 @@ wl_resource_post_no_memory(struct wl_resource *resource) WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); } -static void +static enum wl_iterator_result destroy_resource(void *element, void *data) { struct wl_resource *resource = element; @@ -580,6 +580,8 @@ destroy_resource(void *element, void *data) if (!(flags & WL_MAP_ENTRY_LEGACY)) free(resource); + + return WL_ITERATOR_CONTINUE; } WL_EXPORT void @@ -1604,6 +1606,52 @@ wl_client_add_resource_created_listener(struct wl_client *client, wl_signal_add(&client->resource_created_signal, listener); } +struct wl_resource_iterator_context { + void *user_data; + wl_client_for_each_resource_iterator_func_t it; +}; + +static enum wl_iterator_result +resource_iterator_helper(void *res, void *user_data) +{ + struct wl_resource_iterator_context *context = user_data; + struct wl_resource *resource = res; + + return context->it(resource, context->user_data); +} + +/** Iterate over all the resources of a client + * + * \param client The client object + * \param iterator The iterator function + * \param user_data The user data pointer + * + * The function pointed by \a iterator will be called for each + * resource owned by the client. The \a user_data will be passed + * as the second argument of the iterator function. + * If the \a iterator function returns \a WL_ITERATOR_CONTINUE the iteration + * will continue, if it returns \a WL_ITERATOR_STOP it will stop. + * + * Creating and destroying resources while iterating is safe, but new + * resources may or may not be picked up by the iterator. + * + * \sa wl_iterator_result + * + * \memberof wl_client + */ +WL_EXPORT void +wl_client_for_each_resource(struct wl_client *client, + wl_client_for_each_resource_iterator_func_t iterator, + void *user_data) +{ + struct wl_resource_iterator_context context = { + .user_data = user_data, + .it = iterator, + }; + + wl_map_for_each(&client->objects, resource_iterator_helper, &context); +} + /** \cond */ /* Deprecated functions below. */ uint32_t diff --git a/src/wayland-util.c b/src/wayland-util.c index 7467366d..639ccf87 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -359,24 +359,33 @@ wl_map_lookup_flags(struct wl_map *map, uint32_t i) return 0; } -static void +static enum wl_iterator_result for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) { union map_entry *start, *end, *p; + enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; start = entries->data; end = (union map_entry *) ((char *) entries->data + entries->size); for (p = start; p < end; p++) - if (p->data && !map_entry_is_free(*p)) - func(map_entry_get_data(*p), data); + if (p->data && !map_entry_is_free(*p)) { + ret = func(map_entry_get_data(*p), data); + if (ret != WL_ITERATOR_CONTINUE) + break; + } + + return ret; } WL_EXPORT void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) { - for_each_helper(&map->client_entries, func, data); - for_each_helper(&map->server_entries, func, data); + enum wl_iterator_result ret; + + ret = for_each_helper(&map->client_entries, func, data); + if (ret == WL_ITERATOR_CONTINUE) + for_each_helper(&map->server_entries, func, data); } static void diff --git a/src/wayland-util.h b/src/wayland-util.h index 8da156c0..cacc122a 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -311,6 +311,17 @@ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0); +/** \enum wl_iterator_result + * + * This enum represents the return value of an iterator function. + */ +enum wl_iterator_result { + /** Stop the iteration */ + WL_ITERATOR_STOP, + /** Continue the iteration */ + WL_ITERATOR_CONTINUE +}; + #ifdef __cplusplus } #endif From 450f06e21a3dc772b96de12d81ea27d665f8b33c Mon Sep 17 00:00:00 2001 From: Giulio Camuffo <giuliocamuffo@gmail.com> Date: Fri, 12 Aug 2016 09:33:06 +0200 Subject: [PATCH 0350/1152] Add API to install protocol loggers on the server wl_display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new wl_display_add_protocol_logger allows to set a function as a logger, which will get called when a new request is received or an event is sent. This is akin to setting WAYLAND_DEBUG=1, but more powerful because it can be enabled at run time and allows to show the log e.g. in a UI view. A test is added for the new functionality. Signed-off-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- Makefile.am | 5 +- src/wayland-server-core.h | 24 ++++++ src/wayland-server.c | 102 ++++++++++++++++++++++-- tests/protocol-logger-test.c | 148 +++++++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+), 7 deletions(-) create mode 100644 tests/protocol-logger-test.c diff --git a/Makefile.am b/Makefile.am index e684a871..3eb6fd53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -161,7 +161,8 @@ TESTS = \ resources-test \ message-test \ headers-test \ - compositor-introspection-test + compositor-introspection-test \ + protocol-logger-test if ENABLE_CPP_TEST TESTS += cpp-compile-test @@ -220,6 +221,8 @@ message_test_SOURCES = tests/message-test.c message_test_LDADD = libtest-runner.la compositor_introspection_test_SOURCES = tests/compositor-introspection-test.c compositor_introspection_test_LDADD = libtest-runner.la +protocol_logger_test_SOURCES = tests/protocol-logger-test.c +protocol_logger_test_LDADD = libtest-runner.la headers_test_SOURCES = tests/headers-test.c \ tests/headers-protocol-test.c \ tests/headers-protocol-core-test.c diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 56e8d802..21465af2 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -522,6 +522,30 @@ wl_shm_buffer_create(struct wl_client *client, void wl_log_set_handler_server(wl_log_func_t handler); +enum wl_protocol_logger_type { + WL_PROTOCOL_LOGGER_REQUEST, + WL_PROTOCOL_LOGGER_EVENT, +}; + +struct wl_protocol_logger_message { + struct wl_resource *resource; + int message_opcode; + const struct wl_message *message; + int arguments_count; + const union wl_argument *arguments; +}; + +typedef void (*wl_protocol_logger_func_t)(void *user_data, + enum wl_protocol_logger_type direction, + const struct wl_protocol_logger_message *message); + +struct wl_protocol_logger * +wl_display_add_protocol_logger(struct wl_display *display, + wl_protocol_logger_func_t, void *user_data); + +void +wl_protocol_logger_destroy(struct wl_protocol_logger *logger); + #ifdef __cplusplus } #endif diff --git a/src/wayland-server.c b/src/wayland-server.c index dd648ac2..9ecfd976 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -95,6 +95,7 @@ struct wl_display { struct wl_list global_list; struct wl_list socket_list; struct wl_list client_list; + struct wl_list protocol_loggers; struct wl_signal destroy_signal; struct wl_signal create_client_signal; @@ -123,8 +124,42 @@ struct wl_resource { wl_dispatcher_func_t dispatcher; }; +struct wl_protocol_logger { + struct wl_list link; + wl_protocol_logger_func_t func; + void *user_data; +}; + static int debug_server = 0; +static void +log_closure(struct wl_resource *resource, + struct wl_closure *closure, int send) +{ + struct wl_object *object = &resource->object; + struct wl_display *display = resource->client->display; + struct wl_protocol_logger *protocol_logger; + struct wl_protocol_logger_message message; + + if (debug_server) + wl_closure_print(closure, object, send); + + if (!wl_list_empty(&display->protocol_loggers)) { + message.resource = resource; + message.message_opcode = closure->opcode; + message.message = closure->message; + message.arguments_count = closure->count; + message.arguments = closure->args; + wl_list_for_each(protocol_logger, + &display->protocol_loggers, link) { + protocol_logger->func(protocol_logger->user_data, + send ? WL_PROTOCOL_LOGGER_EVENT : + WL_PROTOCOL_LOGGER_REQUEST, + &message); + } + } +} + WL_EXPORT void wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args) @@ -143,8 +178,7 @@ wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, if (wl_closure_send(closure, resource->client->connection)) resource->client->error = 1; - if (debug_server) - wl_closure_print(closure, object, true); + log_closure(resource, closure, true); wl_closure_destroy(closure); } @@ -183,8 +217,7 @@ wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, if (wl_closure_queue(closure, resource->client->connection)) resource->client->error = 1; - if (debug_server) - wl_closure_print(closure, object, true); + log_closure(resource, closure, true); wl_closure_destroy(closure); } @@ -331,8 +364,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) break; } - if (debug_server) - wl_closure_print(closure, object, false); + log_closure(resource, closure, false); if ((resource_flags & WL_MAP_ENTRY_LEGACY) || resource->dispatcher == NULL) { @@ -885,6 +917,7 @@ wl_display_create(void) wl_list_init(&display->socket_list); wl_list_init(&display->client_list); wl_list_init(&display->registry_resource_list); + wl_list_init(&display->protocol_loggers); wl_signal_init(&display->destroy_signal); wl_signal_init(&display->create_client_signal); @@ -961,6 +994,8 @@ wl_display_destroy(struct wl_display *display) wl_array_release(&display->additional_shm_formats); + wl_list_remove(&display->protocol_loggers); + free(display); } @@ -1481,6 +1516,61 @@ wl_log_set_handler_server(wl_log_func_t handler) wl_log_handler = handler; } +/** Adds a new protocol logger. + * + * When a new protocol message arrives or is sent from the server + * all the protocol logger functions will be called, carrying the + * \a user_data pointer, the type of the message (request or + * event) and the actual message. + * The lifetime of the messages passed to the logger function ends + * when they return so the messages cannot be stored and accessed + * later. + * + * \a errno is set on error. + * + * \param func The function to call to log a new protocol message + * \param user_data The user data pointer to pass to \a func + * + * \return The protol logger object on success, NULL on failure. + * + * \sa wl_protocol_logger_destroy + * + * \memberof wl_display + */ +WL_EXPORT struct wl_protocol_logger * +wl_display_add_protocol_logger(struct wl_display *display, + wl_protocol_logger_func_t func, void *user_data) +{ + struct wl_protocol_logger *logger; + + logger = malloc(sizeof *logger); + if (!logger) + return NULL; + + logger->func = func; + logger->user_data = user_data; + wl_list_insert(&display->protocol_loggers, &logger->link); + + return logger; +} + +/** Destroys a protocol logger. + * + * This function destroys a protocol logger and removes it from the display + * it was added to with \a wl_display_add_protocol_logger. + * The \a logger object becomes invalid after calling this function. + * + * \sa wl_display_add_protocol_logger + * + * \memberof wl_protocol_logger + */ +WL_EXPORT void +wl_protocol_logger_destroy(struct wl_protocol_logger *logger) +{ + wl_list_remove(&logger->link); + free(logger); +} + /** Add support for a wl_shm pixel format * * \param display The display object diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c new file mode 100644 index 00000000..80c74aae --- /dev/null +++ b/tests/protocol-logger-test.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/un.h> +#include <unistd.h> + +#include "wayland-client.h" +#include "wayland-server.h" +#include "test-runner.h" + +/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ +static const char * +require_xdg_runtime_dir(void) +{ + char *val = getenv("XDG_RUNTIME_DIR"); + assert(val && "set $XDG_RUNTIME_DIR to run this test"); + + return val; +} + +struct compositor { + struct wl_display *display; + struct wl_event_loop *loop; + int message; + struct wl_client *client; +}; + +struct message { + enum wl_protocol_logger_type type; + const char *class; + int opcode; + const char *message_name; + int args_count; +} messages[] = { + { + .type = WL_PROTOCOL_LOGGER_REQUEST, + .class = "wl_display", + .opcode = 0, + .message_name = "sync", + .args_count = 1, + }, + { + .type = WL_PROTOCOL_LOGGER_EVENT, + .class = "wl_callback", + .opcode = 0, + .message_name = "done", + .args_count = 1, + }, + { + .type = WL_PROTOCOL_LOGGER_EVENT, + .class = "wl_display", + .opcode = 1, + .message_name = "delete_id", + .args_count = 1, + }, +}; + +static void +logger_func(void *user_data, enum wl_protocol_logger_type type, + const struct wl_protocol_logger_message *message) +{ + struct compositor *c = user_data; + struct message *msg = &messages[c->message++]; + + assert(msg->type == type); + assert(strcmp(msg->class, wl_resource_get_class(message->resource)) == 0); + assert(msg->opcode == message->message_opcode); + assert(strcmp(msg->message_name, message->message->name) == 0); + assert(msg->args_count == message->arguments_count); + + c->client = wl_resource_get_client(message->resource); +} + +static void +callback_done(void *data, struct wl_callback *cb, uint32_t time) +{ + wl_callback_destroy(cb); +} + +static const struct wl_callback_listener callback_listener = { + callback_done, +}; + +TEST(logger) +{ + test_set_timeout(1); + + const char *socket; + struct compositor compositor = { 0 }; + struct { + struct wl_display *display; + struct wl_callback *cb; + } client; + struct wl_protocol_logger *logger; + + require_xdg_runtime_dir(); + + compositor.display = wl_display_create(); + compositor.loop = wl_display_get_event_loop(compositor.display); + socket = wl_display_add_socket_auto(compositor.display); + + logger = wl_display_add_protocol_logger(compositor.display, + logger_func, &compositor); + + client.display = wl_display_connect(socket); + client.cb = wl_display_sync(client.display); + wl_callback_add_listener(client.cb, &callback_listener, NULL); + wl_display_flush(client.display); + + while (compositor.message < 3) { + wl_event_loop_dispatch(compositor.loop, -1); + wl_display_flush_clients(compositor.display); + } + + wl_display_dispatch(client.display); + wl_display_disconnect(client.display); + + wl_client_destroy(compositor.client); + wl_protocol_logger_destroy(logger); + wl_display_destroy(compositor.display); +} From 1c3213adf02ed27e37401929956d9bf79c23dce7 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 12:13:37 -0700 Subject: [PATCH 0351/1152] server: Add doxygen comment for wl_client_for_each Commit 596024f728b0a1292ee69a80dd72a85167870936 includes a doc comment with a link to the wl_client_for_each macro, causing an error when generating documentation. Add a doc comment to wl_client_for_each, enabling the hyperlink and removing the error. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- src/wayland-server-core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 21465af2..2c215e4c 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -180,6 +180,7 @@ wl_client_get_link(struct wl_client *client); struct wl_client * wl_client_from_link(struct wl_list *link); +/** Iterate over a list of clients. */ #define wl_client_for_each(client, list) \ for (client = wl_client_from_link((list)->next); \ wl_client_get_link(client) != (list); \ From d7cb6c357023e2c224c169755cdb80a17c8c79aa Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:32:58 -0700 Subject: [PATCH 0352/1152] protocol: Add summary attributes to request params and enum entries Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 345 ++++++++++++++++++++++--------------------- 1 file changed, 178 insertions(+), 167 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 0830afcd..8793293a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -48,7 +48,8 @@ The callback_data passed in the callback is the event serial. </description> - <arg name="callback" type="new_id" interface="wl_callback"/> + <arg name="callback" type="new_id" interface="wl_callback" + summary="callback object for the sync request"/> </request> <request name="get_registry"> @@ -57,7 +58,8 @@ to list and bind the global objects available from the compositor. </description> - <arg name="registry" type="new_id" interface="wl_registry"/> + <arg name="registry" type="new_id" interface="wl_registry" + summary="global registry object"/> </request> <event name="error"> @@ -129,8 +131,8 @@ Binds a new, client-created object to the server using the specified name as the identifier. </description> - <arg name="name" type="uint" summary="unique name for the object"/> - <arg name="id" type="new_id"/> + <arg name="name" type="uint" summary="unique numeric name of the object"/> + <arg name="id" type="new_id" summary="bounded object"/> </request> <event name="global"> @@ -187,14 +189,14 @@ <description summary="create new surface"> Ask the compositor to create a new surface. </description> - <arg name="id" type="new_id" interface="wl_surface"/> + <arg name="id" type="new_id" interface="wl_surface" summary="the new surface"/> </request> <request name="create_region"> <description summary="create new region"> Ask the compositor to create a new region. </description> - <arg name="id" type="new_id" interface="wl_region"/> + <arg name="id" type="new_id" interface="wl_region" summary="the new region"/> </request> </interface> @@ -224,12 +226,12 @@ a buffer from it. </description> - <arg name="id" type="new_id" interface="wl_buffer"/> - <arg name="offset" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> - <arg name="stride" type="int"/> - <arg name="format" type="uint" enum="wl_shm.format"/> + <arg name="id" type="new_id" interface="wl_buffer" summary="buffer to create"/> + <arg name="offset" type="int" summary="buffer byte offset within the pool"/> + <arg name="width" type="int" summary="buffer width, in pixels"/> + <arg name="height" type="int" summary="buffer height, in pixels"/> + <arg name="stride" type="int" summary="number of bytes from the beginning of one row to the beginning of the next row"/> + <arg name="format" type="uint" enum="wl_shm.format" summary="buffer pixel format"/> </request> <request name="destroy" type="destructor"> @@ -250,7 +252,7 @@ used to make the pool bigger. </description> - <arg name="size" type="int"/> + <arg name="size" type="int" summary="new size of the pool, in bytes"/> </request> </interface> @@ -283,68 +285,69 @@ All renderers should support argb8888 and xrgb8888 but any other formats are optional and may not be supported by the particular renderer in use. + + The drm format codes match the #defines in drm_fourcc.h. + The formats actually supported by the compositor will be + reported by the format event. </description> - <entry name="argb8888" value="0" summary="32-bit ARGB format"/> - <entry name="xrgb8888" value="1" summary="32-bit RGB format"/> - <!-- The drm format codes match the #defines in drm_fourcc.h. - The formats actually supported by the compositor will be - reported by the format event. --> - <entry name="c8" value="0x20203843"/> - <entry name="rgb332" value="0x38424752"/> - <entry name="bgr233" value="0x38524742"/> - <entry name="xrgb4444" value="0x32315258"/> - <entry name="xbgr4444" value="0x32314258"/> - <entry name="rgbx4444" value="0x32315852"/> - <entry name="bgrx4444" value="0x32315842"/> - <entry name="argb4444" value="0x32315241"/> - <entry name="abgr4444" value="0x32314241"/> - <entry name="rgba4444" value="0x32314152"/> - <entry name="bgra4444" value="0x32314142"/> - <entry name="xrgb1555" value="0x35315258"/> - <entry name="xbgr1555" value="0x35314258"/> - <entry name="rgbx5551" value="0x35315852"/> - <entry name="bgrx5551" value="0x35315842"/> - <entry name="argb1555" value="0x35315241"/> - <entry name="abgr1555" value="0x35314241"/> - <entry name="rgba5551" value="0x35314152"/> - <entry name="bgra5551" value="0x35314142"/> - <entry name="rgb565" value="0x36314752"/> - <entry name="bgr565" value="0x36314742"/> - <entry name="rgb888" value="0x34324752"/> - <entry name="bgr888" value="0x34324742"/> - <entry name="xbgr8888" value="0x34324258"/> - <entry name="rgbx8888" value="0x34325852"/> - <entry name="bgrx8888" value="0x34325842"/> - <entry name="abgr8888" value="0x34324241"/> - <entry name="rgba8888" value="0x34324152"/> - <entry name="bgra8888" value="0x34324142"/> - <entry name="xrgb2101010" value="0x30335258"/> - <entry name="xbgr2101010" value="0x30334258"/> - <entry name="rgbx1010102" value="0x30335852"/> - <entry name="bgrx1010102" value="0x30335842"/> - <entry name="argb2101010" value="0x30335241"/> - <entry name="abgr2101010" value="0x30334241"/> - <entry name="rgba1010102" value="0x30334152"/> - <entry name="bgra1010102" value="0x30334142"/> - <entry name="yuyv" value="0x56595559"/> - <entry name="yvyu" value="0x55595659"/> - <entry name="uyvy" value="0x59565955"/> - <entry name="vyuy" value="0x59555956"/> - <entry name="ayuv" value="0x56555941"/> - <entry name="nv12" value="0x3231564e"/> - <entry name="nv21" value="0x3132564e"/> - <entry name="nv16" value="0x3631564e"/> - <entry name="nv61" value="0x3136564e"/> - <entry name="yuv410" value="0x39565559"/> - <entry name="yvu410" value="0x39555659"/> - <entry name="yuv411" value="0x31315559"/> - <entry name="yvu411" value="0x31315659"/> - <entry name="yuv420" value="0x32315559"/> - <entry name="yvu420" value="0x32315659"/> - <entry name="yuv422" value="0x36315559"/> - <entry name="yvu422" value="0x36315659"/> - <entry name="yuv444" value="0x34325559"/> - <entry name="yvu444" value="0x34325659"/> + <entry name="argb8888" value="0" summary="32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian"/> + <entry name="xrgb8888" value="1" summary="32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian"/> + <entry name="c8" value="0x20203843" summary="8-bit color index format, [7:0] C"/> + <entry name="rgb332" value="0x38424752" summary="8-bit RGB format, [7:0] R:G:B 3:3:2"/> + <entry name="bgr233" value="0x38524742" summary="8-bit BGR format, [7:0] B:G:R 2:3:3"/> + <entry name="xrgb4444" value="0x32315258" summary="16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian"/> + <entry name="xbgr4444" value="0x32314258" summary="16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian"/> + <entry name="rgbx4444" value="0x32315852" summary="16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian"/> + <entry name="bgrx4444" value="0x32315842" summary="16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian"/> + <entry name="argb4444" value="0x32315241" summary="16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian"/> + <entry name="abgr4444" value="0x32314241" summary="16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian"/> + <entry name="rgba4444" value="0x32314152" summary="16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian"/> + <entry name="bgra4444" value="0x32314142" summary="16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian"/> + <entry name="xrgb1555" value="0x35315258" summary="16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian"/> + <entry name="xbgr1555" value="0x35314258" summary="16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian"/> + <entry name="rgbx5551" value="0x35315852" summary="16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian"/> + <entry name="bgrx5551" value="0x35315842" summary="16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian"/> + <entry name="argb1555" value="0x35315241" summary="16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian"/> + <entry name="abgr1555" value="0x35314241" summary="16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian"/> + <entry name="rgba5551" value="0x35314152" summary="16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian"/> + <entry name="bgra5551" value="0x35314142" summary="16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian"/> + <entry name="rgb565" value="0x36314752" summary="16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian"/> + <entry name="bgr565" value="0x36314742" summary="16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian"/> + <entry name="rgb888" value="0x34324752" summary="24-bit RGB format, [23:0] R:G:B little endian"/> + <entry name="bgr888" value="0x34324742" summary="24-bit BGR format, [23:0] B:G:R little endian"/> + <entry name="xbgr8888" value="0x34324258" summary="32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian"/> + <entry name="rgbx8888" value="0x34325852" summary="32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian"/> + <entry name="bgrx8888" value="0x34325842" summary="32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian"/> + <entry name="abgr8888" value="0x34324241" summary="32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian"/> + <entry name="rgba8888" value="0x34324152" summary="32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian"/> + <entry name="bgra8888" value="0x34324142" summary="32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian"/> + <entry name="xrgb2101010" value="0x30335258" summary="32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian"/> + <entry name="xbgr2101010" value="0x30334258" summary="32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian"/> + <entry name="rgbx1010102" value="0x30335852" summary="32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian"/> + <entry name="bgrx1010102" value="0x30335842" summary="32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian"/> + <entry name="argb2101010" value="0x30335241" summary="32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian"/> + <entry name="abgr2101010" value="0x30334241" summary="32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian"/> + <entry name="rgba1010102" value="0x30334152" summary="32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian"/> + <entry name="bgra1010102" value="0x30334142" summary="32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian"/> + <entry name="yuyv" value="0x56595559" summary="packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian"/> + <entry name="yvyu" value="0x55595659" summary="packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian"/> + <entry name="uyvy" value="0x59565955" summary="packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian"/> + <entry name="vyuy" value="0x59555956" summary="packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian"/> + <entry name="ayuv" value="0x56555941" summary="packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian"/> + <entry name="nv12" value="0x3231564e" summary="2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane"/> + <entry name="nv21" value="0x3132564e" summary="2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane"/> + <entry name="nv16" value="0x3631564e" summary="2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane"/> + <entry name="nv61" value="0x3136564e" summary="2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane"/> + <entry name="yuv410" value="0x39565559" summary="3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes"/> + <entry name="yvu410" value="0x39555659" summary="3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes"/> + <entry name="yuv411" value="0x31315559" summary="3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes"/> + <entry name="yvu411" value="0x31315659" summary="3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes"/> + <entry name="yuv420" value="0x32315559" summary="3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes"/> + <entry name="yvu420" value="0x32315659" summary="3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes"/> + <entry name="yuv422" value="0x36315559" summary="3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes"/> + <entry name="yvu422" value="0x36315659" summary="3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes"/> + <entry name="yuv444" value="0x34325559" summary="3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes"/> + <entry name="yvu444" value="0x34325659" summary="3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes"/> </enum> <request name="create_pool"> @@ -356,9 +359,9 @@ descriptor, to use as backing memory for the pool. </description> - <arg name="id" type="new_id" interface="wl_shm_pool"/> - <arg name="fd" type="fd"/> - <arg name="size" type="int"/> + <arg name="id" type="new_id" interface="wl_shm_pool" summary="pool to create"/> + <arg name="fd" type="fd" summary="file descriptor for the pool"/> + <arg name="size" type="int" summary="pool size, in bytes"/> </request> <event name="format"> @@ -446,8 +449,8 @@ conjunction with wl_data_source.action for feedback. </description> - <arg name="serial" type="uint"/> - <arg name="mime_type" type="string" allow-null="true"/> + <arg name="serial" type="uint" summary="serial number of the accept request"/> + <arg name="mime_type" type="string" allow-null="true" summary="mime type accepted by the client"/> </request> <request name="receive"> @@ -468,8 +471,8 @@ clients may preemptively fetch data or examine it more closely to determine acceptance. </description> - <arg name="mime_type" type="string"/> - <arg name="fd" type="fd"/> + <arg name="mime_type" type="string" summary="mime type desired by receiver"/> + <arg name="fd" type="fd" summary="file descriptor for data transfer"/> </request> <request name="destroy" type="destructor"> @@ -539,8 +542,8 @@ This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise. </description> - <arg name="dnd_actions" type="uint"/> - <arg name="preferred_action" type="uint"/> + <arg name="dnd_actions" type="uint" summary="actions supported by the destination client"/> + <arg name="preferred_action" type="uint" summary="action preferred by the destination client"/> </request> <event name="source_actions" since="3"> @@ -615,7 +618,7 @@ advertised to targets. Can be called several times to offer multiple types. </description> - <arg name="mime_type" type="string"/> + <arg name="mime_type" type="string" summary="mime type offered by the data source"/> </request> <request name="destroy" type="destructor"> @@ -689,7 +692,7 @@ wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error. </description> - <arg name="dnd_actions" type="uint"/> + <arg name="dnd_actions" type="uint" summary="actions supported by the data source"/> </request> <event name="dnd_drop_performed" since="3"> @@ -792,10 +795,10 @@ as an icon ends, the current and pending input regions become undefined, and the wl_surface is unmapped. </description> - <arg name="source" type="object" interface="wl_data_source" allow-null="true"/> - <arg name="origin" type="object" interface="wl_surface"/> - <arg name="icon" type="object" interface="wl_surface" allow-null="true"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the origin"/> + <arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the eventual transfer"/> + <arg name="origin" type="object" interface="wl_surface" summary="surface where the drag originates"/> + <arg name="icon" type="object" interface="wl_surface" allow-null="true" summary="drag-and-drop icon surface"/> + <arg name="serial" type="uint" summary="serial number of the implicit grab on the origin"/> </request> <request name="set_selection"> @@ -805,8 +808,8 @@ To unset the selection, set the source to NULL. </description> - <arg name="source" type="object" interface="wl_data_source" allow-null="true"/> - <arg name="serial" type="uint" summary="serial of the event that triggered this request"/> + <arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the selection"/> + <arg name="serial" type="uint" summary="serial number of the event that triggered this request"/> </request> <event name="data_offer"> @@ -922,15 +925,15 @@ <description summary="create a new data source"> Create a new data source. </description> - <arg name="id" type="new_id" interface="wl_data_source"/> + <arg name="id" type="new_id" interface="wl_data_source" summary="data source to create"/> </request> <request name="get_data_device"> <description summary="create a new data device"> Create a new data device for a given seat. </description> - <arg name="id" type="new_id" interface="wl_data_device"/> - <arg name="seat" type="object" interface="wl_seat"/> + <arg name="id" type="new_id" interface="wl_data_device" summary="data device to create"/> + <arg name="seat" type="object" interface="wl_seat" summary="seat associated with the data device"/> </request> <!-- Version 3 additions --> @@ -961,10 +964,10 @@ or drags initiated with other buttons than BTN_LEFT to specific actions (e.g. "ask"). </description> - <entry name="none" value="0"/> - <entry name="copy" value="1"/> - <entry name="move" value="2"/> - <entry name="ask" value="4"/> + <entry name="none" value="0" summary="no action"/> + <entry name="copy" value="1" summary="copy action"/> + <entry name="move" value="2" summary="move action"/> + <entry name="ask" value="4" summary="ask action"/> </enum> </interface> @@ -989,8 +992,8 @@ Only one shell surface can be associated with a given surface. </description> - <arg name="id" type="new_id" interface="wl_shell_surface"/> - <arg name="surface" type="object" interface="wl_surface"/> + <arg name="id" type="new_id" interface="wl_shell_surface" summary="shell surface to create"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface to be given the shell surface role"/> </request> </interface> @@ -1036,15 +1039,15 @@ use this information to adapt its behavior, e.g. choose an appropriate cursor image. </description> - <entry name="none" value="0"/> - <entry name="top" value="1"/> - <entry name="bottom" value="2"/> - <entry name="left" value="4"/> - <entry name="top_left" value="5"/> - <entry name="bottom_left" value="6"/> - <entry name="right" value="8"/> - <entry name="top_right" value="9"/> - <entry name="bottom_right" value="10"/> + <entry name="none" value="0" summary="no edge"/> + <entry name="top" value="1" summary="top edge"/> + <entry name="bottom" value="2" summary="bottom edge"/> + <entry name="left" value="4" summary="left edge"/> + <entry name="top_left" value="5" summary="top and left edges"/> + <entry name="bottom_left" value="6" summary="bottom and left edges"/> + <entry name="right" value="8" summary="right edge"/> + <entry name="top_right" value="9" summary="top and right edges"/> + <entry name="bottom_right" value="10" summary="bottom and right edges"/> </enum> <request name="resize"> @@ -1087,10 +1090,10 @@ The flags argument controls details of the transient behaviour. </description> - <arg name="parent" type="object" interface="wl_surface"/> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="flags" type="uint" enum="transient"/> + <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/> + <arg name="x" type="int" summary="surface-local x coordinate"/> + <arg name="y" type="int" summary="surface-local y coordinate"/> + <arg name="flags" type="uint" enum="transient" summary="transient surface behavior"/> </request> <enum name="fullscreen_method"> @@ -1141,9 +1144,10 @@ with the dimensions for the output on which the surface will be made fullscreen. </description> - <arg name="method" type="uint" enum="fullscreen_method"/> - <arg name="framerate" type="uint"/> - <arg name="output" type="object" interface="wl_output" allow-null="true"/> + <arg name="method" type="uint" enum="fullscreen_method" summary="method for resolving size conflict"/> + <arg name="framerate" type="uint" summary="framerate in mHz"/> + <arg name="output" type="object" interface="wl_output" allow-null="true" + summary="output on which the surface is to be fullscreen"/> </request> <request name="set_popup"> @@ -1171,10 +1175,10 @@ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> - <arg name="parent" type="object" interface="wl_surface"/> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="flags" type="uint" enum="transient"/> + <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/> + <arg name="x" type="int" summary="surface-local x coordinate"/> + <arg name="y" type="int" summary="surface-local y coordinate"/> + <arg name="flags" type="uint" enum="transient" summary="transient surface behavior"/> </request> <request name="set_maximized"> @@ -1198,7 +1202,8 @@ The details depend on the compositor implementation. </description> - <arg name="output" type="object" interface="wl_output" allow-null="true"/> + <arg name="output" type="object" interface="wl_output" allow-null="true" + summary="output on which the surface is to be maximized"/> </request> <request name="set_title"> @@ -1211,7 +1216,7 @@ The string must be encoded in UTF-8. </description> - <arg name="title" type="string"/> + <arg name="title" type="string" summary="surface title"/> </request> <request name="set_class"> @@ -1223,7 +1228,7 @@ file name (or the full path if it is a non-standard location) of the application's .desktop file as the class. </description> - <arg name="class_" type="string"/> + <arg name="class_" type="string" summary="surface class"/> </request> <event name="ping"> @@ -1369,9 +1374,10 @@ following wl_surface.commit will remove the surface content. </description> - <arg name="buffer" type="object" interface="wl_buffer" allow-null="true"/> - <arg name="x" type="int"/> - <arg name="y" type="int"/> + <arg name="buffer" type="object" interface="wl_buffer" allow-null="true" + summary="buffer of surface contents"/> + <arg name="x" type="int" summary="surface-local x coordinate"/> + <arg name="y" type="int" summary="surface-local y coordinate"/> </request> <request name="damage"> @@ -1398,10 +1404,10 @@ and is probably the preferred and intuitive way of doing this. </description> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> + <arg name="x" type="int" summary="surface-local x coordinate"/> + <arg name="y" type="int" summary="surface-local y coordinate"/> + <arg name="width" type="int" summary="width of damage rectangle"/> + <arg name="height" type="int" summary="height of damage rectangle"/> </request> <request name="frame"> @@ -1440,7 +1446,7 @@ milliseconds, with an undefined base. </description> - <arg name="callback" type="new_id" interface="wl_callback"/> + <arg name="callback" type="new_id" interface="wl_callback" summary="callback object for the frame request"/> </request> <request name="set_opaque_region"> @@ -1471,7 +1477,8 @@ region to be set to empty. </description> - <arg name="region" type="object" interface="wl_region" allow-null="true"/> + <arg name="region" type="object" interface="wl_region" allow-null="true" + summary="opaque region of the surface"/> </request> <request name="set_input_region"> @@ -1500,7 +1507,8 @@ to infinite. </description> - <arg name="region" type="object" interface="wl_region" allow-null="true"/> + <arg name="region" type="object" interface="wl_region" allow-null="true" + summary="input region of the surface"/> </request> <request name="commit"> @@ -1579,7 +1587,8 @@ wl_output.transform enum the invalid_transform protocol error is raised. </description> - <arg name="transform" type="int" enum="wl_output.transform"/> + <arg name="transform" type="int" enum="wl_output.transform" + summary="transform for interpreting buffer contents"/> </request> <!-- Version 3 additions --> @@ -1610,7 +1619,8 @@ If scale is not positive the invalid_scale protocol error is raised. </description> - <arg name="scale" type="int"/> + <arg name="scale" type="int" + summary="positive scale for interpreting buffer contents"/> </request> <!-- Version 4 additions --> @@ -1649,10 +1659,10 @@ after receiving the wl_surface.commit. </description> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> + <arg name="x" type="int" summary="buffer-local x coordinate"/> + <arg name="y" type="int" summary="buffer-local y coordinate"/> + <arg name="width" type="int" summary="width of damage rectangle"/> + <arg name="height" type="int" summary="height of damage rectangle"/> </request> </interface> @@ -1714,7 +1724,7 @@ It is a protocol violation to issue this request on a seat that has never had the pointer capability. </description> - <arg name="id" type="new_id" interface="wl_pointer"/> + <arg name="id" type="new_id" interface="wl_pointer" summary="seat pointer"/> </request> <request name="get_keyboard"> @@ -1727,7 +1737,7 @@ It is a protocol violation to issue this request on a seat that has never had the keyboard capability. </description> - <arg name="id" type="new_id" interface="wl_keyboard"/> + <arg name="id" type="new_id" interface="wl_keyboard" summary="seat keyboard"/> </request> <request name="get_touch"> @@ -1740,7 +1750,7 @@ It is a protocol violation to issue this request on a seat that has never had the touch capability. </description> - <arg name="id" type="new_id" interface="wl_touch"/> + <arg name="id" type="new_id" interface="wl_touch" summary="seat touch interface"/> </request> <!-- Version 2 additions --> @@ -1817,7 +1827,8 @@ </description> <arg name="serial" type="uint" summary="serial of the enter event"/> - <arg name="surface" type="object" interface="wl_surface" allow-null="true"/> + <arg name="surface" type="object" interface="wl_surface" allow-null="true" + summary="pointer surface"/> <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/> <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/> </request> @@ -1891,8 +1902,8 @@ <description summary="axis types"> Describes the axis types of scroll events. </description> - <entry name="vertical_scroll" value="0"/> - <entry name="horizontal_scroll" value="1"/> + <entry name="vertical_scroll" value="0" summary="vertical axis"/> + <entry name="horizontal_scroll" value="1" summary="horizontal axis"/> </enum> <event name="axis"> @@ -2279,12 +2290,12 @@ This enumeration describes how the physical pixels on an output are laid out. </description> - <entry name="unknown" value="0"/> - <entry name="none" value="1"/> - <entry name="horizontal_rgb" value="2"/> - <entry name="horizontal_bgr" value="3"/> - <entry name="vertical_rgb" value="4"/> - <entry name="vertical_bgr" value="5"/> + <entry name="unknown" value="0" summary="unknown geometry"/> + <entry name="none" value="1" summary="no geometry"/> + <entry name="horizontal_rgb" value="2" summary="horizontal RGB"/> + <entry name="horizontal_bgr" value="3" summary="horizontal BGR"/> + <entry name="vertical_rgb" value="4" summary="vertical RGB"/> + <entry name="vertical_bgr" value="5" summary="vertical BGR"/> </enum> <enum name="transform"> @@ -2302,14 +2313,14 @@ surfaces. </description> - <entry name="normal" value="0"/> - <entry name="90" value="1"/> - <entry name="180" value="2"/> - <entry name="270" value="3"/> - <entry name="flipped" value="4"/> - <entry name="flipped_90" value="5"/> - <entry name="flipped_180" value="6"/> - <entry name="flipped_270" value="7"/> + <entry name="normal" value="0" summary="no transform"/> + <entry name="90" value="1" summary="90 degrees counter-clockwise"/> + <entry name="180" value="2" summary="180 degrees counter-clockwise"/> + <entry name="270" value="3" summary="270 degrees counter-clockwise"/> + <entry name="flipped" value="4" summary="180 degree flip around a vertical axis"/> + <entry name="flipped_90" value="5" summary="flip and rotate 90 degrees counter-clockwise"/> + <entry name="flipped_180" value="6" summary="flip and rotate 180 degrees counter-clockwise"/> + <entry name="flipped_270" value="7" summary="flip and rotate 270 degrees counter-clockwise"/> </enum> <event name="geometry"> @@ -2434,10 +2445,10 @@ Add the specified rectangle to the region. </description> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> + <arg name="x" type="int" summary="region-local x coordinate"/> + <arg name="y" type="int" summary="region-local y coordinate"/> + <arg name="width" type="int" summary="rectangle width"/> + <arg name="height" type="int" summary="rectangle height"/> </request> <request name="subtract"> @@ -2445,10 +2456,10 @@ Subtract the specified rectangle from the region. </description> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> + <arg name="x" type="int" summary="region-local x coordinate"/> + <arg name="y" type="int" summary="region-local y coordinate"/> + <arg name="width" type="int" summary="rectangle width"/> + <arg name="height" type="int" summary="rectangle height"/> </request> </interface> From aaf2c91873d77df2bdc1aa32bd7bf6ced41ac53b Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:32:59 -0700 Subject: [PATCH 0353/1152] protocol: Hyphenate subsurface Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8793293a..b20d35c8 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2511,7 +2511,7 @@ </description> <arg name="id" type="new_id" interface="wl_subsurface" - summary="the new subsurface object ID"/> + summary="the new sub-surface object ID"/> <arg name="surface" type="object" interface="wl_surface" summary="the surface to be turned into a sub-surface"/> <arg name="parent" type="object" interface="wl_surface" From 83ec381bf8e40273c02170028598212f738b9dfd Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:33:00 -0700 Subject: [PATCH 0354/1152] protocol: Capitalize ID for consistency Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index b20d35c8..cc0deac1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -98,7 +98,7 @@ When the client receives this event, it will know that it can safely reuse the object ID. </description> - <arg name="id" type="uint" summary="deleted object id"/> + <arg name="id" type="uint" summary="deleted object ID"/> </event> </interface> From 3f1104d64cd24b0580c0b8c86ca699bf03fe9d1f Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:33:01 -0700 Subject: [PATCH 0355/1152] protocol: Add missing line break Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index cc0deac1..523bd9d9 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -170,6 +170,7 @@ Clients can handle the 'done' event to get notified when the related request is done. </description> + <event name="done"> <description summary="done event"> Notify the client when the related request is done. From 40feca914b94d1d3e2f1f6fc7a22a5ebee014137 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:33:02 -0700 Subject: [PATCH 0356/1152] protocol: Correct description indentation Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 523bd9d9..55a74a71 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -173,7 +173,7 @@ <event name="done"> <description summary="done event"> - Notify the client when the related request is done. + Notify the client when the related request is done. </description> <arg name="callback_data" type="uint" summary="request-specific data for the wl_callback"/> </event> @@ -281,11 +281,11 @@ <enum name="format"> <description summary="pixel formats"> - This describes the memory layout of an individual pixel. + This describes the memory layout of an individual pixel. - All renderers should support argb8888 and xrgb8888 but any other - formats are optional and may not be supported by the particular - renderer in use. + All renderers should support argb8888 and xrgb8888 but any other + formats are optional and may not be supported by the particular + renderer in use. The drm format codes match the #defines in drm_fourcc.h. The formats actually supported by the compositor will be From 7aa1f6cb2f506e49c483a2222a8f971fcf30882c Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:33:03 -0700 Subject: [PATCH 0357/1152] protocol: Remove wl_ prefix from summary descriptions Summary attributes sometime describe objects using their wl-prefixed type, but more often don't. Remove the wl_ prefix from summary descriptions, since they tend to describe concepts. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 55a74a71..ac066f46 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -175,7 +175,7 @@ <description summary="done event"> Notify the client when the related request is done. </description> - <arg name="callback_data" type="uint" summary="request-specific data for the wl_callback"/> + <arg name="callback_data" type="uint" summary="request-specific data for the callback"/> </event> </interface> @@ -1029,7 +1029,7 @@ The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized). </description> - <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> + <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/> <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> </request> @@ -1059,7 +1059,7 @@ The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized). </description> - <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> + <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/> <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> <arg name="edges" type="uint" enum="resize" summary="which edge or corner is being dragged"/> </request> @@ -1174,7 +1174,7 @@ parent surface, in surface-local coordinates. </description> - <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> + <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/> <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/> <arg name="x" type="int" summary="surface-local x coordinate"/> From 8e7e52f3353be3d30dba0c1625c232e6d6e223a3 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:33:04 -0700 Subject: [PATCH 0358/1152] protocol: Describe serial as serial number Change "serial" to "serial number" in arg summaries, for consistency and clarity. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index ac066f46..553274f1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1018,7 +1018,7 @@ A client must respond to a ping event with a pong request or the client may be deemed unresponsive. </description> - <arg name="serial" type="uint" summary="serial of the ping event"/> + <arg name="serial" type="uint" summary="serial number of the ping event"/> </request> <request name="move"> @@ -1030,7 +1030,7 @@ the surface (e.g. fullscreen or maximized). </description> <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/> </request> <enum name="resize" bitfield="true"> @@ -1060,7 +1060,7 @@ the surface (e.g. fullscreen or maximized). </description> <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/> <arg name="edges" type="uint" enum="resize" summary="which edge or corner is being dragged"/> </request> @@ -1175,7 +1175,7 @@ </description> <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/> <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/> <arg name="x" type="int" summary="surface-local x coordinate"/> <arg name="y" type="int" summary="surface-local y coordinate"/> @@ -1827,7 +1827,7 @@ undefined, and the wl_surface is unmapped. </description> - <arg name="serial" type="uint" summary="serial of the enter event"/> + <arg name="serial" type="uint" summary="serial number of the enter event"/> <arg name="surface" type="object" interface="wl_surface" allow-null="true" summary="pointer surface"/> <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/> From a285fa939cb06842ff1e1d5071c9ead8141c1052 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Thu, 11 Aug 2016 14:33:05 -0700 Subject: [PATCH 0359/1152] protocol: Specify upper left corner of damage rectangle Specify x and y args as the upper left corner of the surface / buffer damage rectangle. Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com> --- protocol/wayland.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 553274f1..3f2d967f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1390,7 +1390,8 @@ Damage is double-buffered state, see wl_surface.commit. - The damage rectangle is specified in surface-local coordinates. + The damage rectangle is specified in surface-local coordinates, + where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage @@ -1634,7 +1635,8 @@ Damage is double-buffered state, see wl_surface.commit. - The damage rectangle is specified in buffer coordinates. + The damage rectangle is specified in buffer coordinates, + where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending From 2a6b08896abeb8ce82f381b1abf5daeee53e7d79 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 16 Aug 2016 11:25:12 -0700 Subject: [PATCH 0360/1152] configure.ac: bump to version 1.11.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9af3574f..109b7586 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [11]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 2d7b34e2ee7627e125496c8816f656f485fcfc81 Mon Sep 17 00:00:00 2001 From: Bryce Harrington <bryce@osg.samsung.com> Date: Tue, 30 Aug 2016 11:40:23 -0700 Subject: [PATCH 0361/1152] configure.ac: bump to version 1.11.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 109b7586..5f416a10 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [11]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From d9ef882139e6178edf68c3fce147afdb3b57b894 Mon Sep 17 00:00:00 2001 From: Yong Bakos <ybakos@humanoriented.com> Date: Sun, 4 Sep 2016 10:15:49 -0700 Subject: [PATCH 0362/1152] doc: Correct docbook title The docbook title was "The Wayland display server," which is inaccurate. Change the title to "The Wayland Protocol". Signed-off-by: Yong Bakos <ybakos@humanoriented.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> --- doc/publican/sources/Book_Info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/sources/Book_Info.xml b/doc/publican/sources/Book_Info.xml index e9e5ff0d..0b7bf079 100644 --- a/doc/publican/sources/Book_Info.xml +++ b/doc/publican/sources/Book_Info.xml @@ -5,7 +5,7 @@ ]> <bookinfo id="book-Wayland-Wayland"> <title>Wayland - The Wayland display server + The Wayland Protocol Documentation 0.1 1 From 2bdbb741e2ac0ec9ecc564463a59b3ef8f499f6a Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sun, 4 Sep 2016 13:23:05 -0700 Subject: [PATCH 0363/1152] tests: Add test for wl_list_length list-test.c did not cover wl_list_length, so add one test that specifically tests this method. Signed-off-by: Yong Bakos Reviewed-by: Eric Engestrom Reviewed-by: Pekka Paalanen --- tests/list-test.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/list-test.c b/tests/list-test.c index 21ca4ecb..07526181 100644 --- a/tests/list-test.c +++ b/tests/list-test.c @@ -57,6 +57,19 @@ TEST(list_insert) assert(e.link.prev == &list); } +TEST(list_length) +{ + struct wl_list list; + struct element e; + + wl_list_init(&list); + assert(wl_list_length(&list) == 0); + wl_list_insert(&list, &e.link); + assert(wl_list_length(&list) == 1); + wl_list_remove(&e.link); + assert(wl_list_length(&list) == 0); +} + TEST(list_iterator) { struct wl_list list; From da58173cfe047864d073ba078e0b8db982a31b12 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 6 Sep 2016 14:22:03 -0700 Subject: [PATCH 0364/1152] configure.ac: bump to version 1.11.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5f416a10..429a5907 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [11]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 2c8fc3eae27c9c0b02694c60d46886ebf47cc83c Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Wed, 17 Aug 2016 16:03:31 -0700 Subject: [PATCH 0365/1152] protocol: Replace '#defines' with 'macros' The use of # within a description causes the documentation generator to mistake C syntax with a documentation link. Remove the # from the documentation, suppressing the warning. Signed-off-by: Yong Bakos Reviewed-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3f2d967f..6c6d078a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -287,7 +287,7 @@ formats are optional and may not be supported by the particular renderer in use. - The drm format codes match the #defines in drm_fourcc.h. + The drm format codes match the macros defined in drm_fourcc.h. The formats actually supported by the compositor will be reported by the format event. From 9afa4bfb7b1e8abfb798e25fc28545e60673ed50 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Wed, 17 Aug 2016 16:08:17 -0700 Subject: [PATCH 0366/1152] server: Document display parameter Signed-off-by: Yong Bakos Reviewed-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 9ecfd976..9d7d9c1b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1528,6 +1528,7 @@ wl_log_set_handler_server(wl_log_func_t handler) * * \a errno is set on error. * + * \param display The display object * \param func The function to call to log a new protocol message * \param user_data The user data pointer to pass to \a func * From a4aba37ba178f8400cfdc2b595005bb76d6af2c0 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 13 Sep 2016 12:13:57 -0700 Subject: [PATCH 0367/1152] configure.ac: bump to version 1.11.94 for the RC2 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 429a5907..11e42c48 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [11]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_micro_version], [94]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From a0d76ffda5c3483e5e67fed19b7d8afe8966782c Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 20 Sep 2016 10:45:10 -0700 Subject: [PATCH 0368/1152] configure.ac: bump to version 1.12.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 11e42c48..a21109a6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [11]) -m4_define([wayland_micro_version], [94]) +m4_define([wayland_minor_version], [12]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 454df51dce609dcc805c888cb8611049bdf9ae08 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Thu, 22 Sep 2016 10:31:53 -0700 Subject: [PATCH 0369/1152] configure.ac: bump version to 1.12.90 for open development Signed-off-by: Bryce Harrington --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a21109a6..6cda418d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [12]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From f7e1dcc20bc873cae0ea532f094cbe417626519f Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Thu, 22 Sep 2016 21:59:37 -0500 Subject: [PATCH 0370/1152] util: Document wl_list methods Add doxygen comment blocks to all wl_list methods. Signed-off-by: Yong Bakos Reviewed-by: Bryce Harrington [Pekka: removed "itself" as suggested by Bryce] Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 224 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 184 insertions(+), 40 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index cacc122a..a4043901 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -78,73 +78,150 @@ struct wl_interface { /** \class wl_list * - * \brief doubly-linked list + * \brief Doubly-linked list * - * The list head is of "struct wl_list" type, and must be initialized - * using wl_list_init(). All entries in the list must be of the same - * type. The item type must have a "struct wl_list" member. This - * member will be initialized by wl_list_insert(). There is no need to - * call wl_list_init() on the individual item. To query if the list is - * empty in O(1), use wl_list_empty(). + * On its own, an instance of `struct wl_list` represents the sentinel head of + * a doubly-linked list, and must be initialized using wl_list_init(). + * When empty, the list head's `next` and `prev` members point to the list head + * itself, otherwise `next` references the first element in the list, and `prev` + * refers to the last element in the list. * - * Let's call the list reference "struct wl_list foo_list", the item type as - * "item_t", and the item member as "struct wl_list link". + * Use the `struct wl_list` type to represent both the list head and the links + * between elements within the list. Use wl_list_empty() to determine if the + * list is empty in O(1). + * + * All elements in the list must be of the same type. The element type must have + * a `struct wl_list` member, often named `link` by convention. Prior to + * insertion, there is no need to initialize an element's `link` - invoking + * wl_list_init() on an individual list element's `struct wl_list` member is + * unnecessary if the very next operation is wl_list_insert(). However, a + * common idiom is to initialize an element's `link` prior to removal - ensure + * safety by invoking wl_list_init() before wl_list_remove(). + * + * Consider a list reference `struct wl_list foo_list`, an element type as + * `struct element`, and an element's link member as `struct wl_list link`. + * + * The following code initializes a list and adds three elements to it. * - * The following code will initialize a list: * \code * struct wl_list foo_list; * - * struct item_t { - * int foo; - * struct wl_list link; + * struct element { + * int foo; + * struct wl_list link; * }; - * struct item_t item1, item2, item3; + * struct element e1, e2, e3; * * wl_list_init(&foo_list); - * wl_list_insert(&foo_list, &item1.link); // Pushes item1 at the head - * wl_list_insert(&foo_list, &item2.link); // Pushes item2 at the head - * wl_list_insert(&item2.link, &item3.link); // Pushes item3 after item2 + * wl_list_insert(&foo_list, &e1.link); // e1 is the first element + * wl_list_insert(&foo_list, &e2.link); // e2 is now the first element + * wl_list_insert(&e2.link, &e3.link); // insert e3 after e2 * \endcode * - * The list now looks like [item2, item3, item1] + * The list now looks like [e2, e3, e1]. + * + * The `wl_list` API provides some iterator macros. For example, to iterate + * a list in ascending order: * - * Iterate the list in ascending order: * \code - * item_t *item; - * wl_list_for_each(item, foo_list, link) { - * Do_something_with_item(item); + * struct element *e; + * wl_list_for_each(e, foo_list, link) { + * do_something_with_element(e); * } * \endcode + * + * See the documentation of each iterator for details. + * \sa http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/list.h */ struct wl_list { struct wl_list *prev; struct wl_list *next; }; +/** + * Initializes the list. + * + * \param list List to initialize + * + * \memberof wl_list + */ void wl_list_init(struct wl_list *list); +/** + * Inserts an element into the list, after the element represented by \p list. + * When \p list is a reference to the list itself (the head), set the containing + * struct of \p elm as the first element in the list. + * + * \note If \p elm is already part of a list, inserting it again will lead to + * list corruption. + * + * \param list List element after which the new element is inserted + * \param elm Link of the containing struct to insert into the list + * + * \memberof wl_list + */ void wl_list_insert(struct wl_list *list, struct wl_list *elm); +/** + * Removes an element from the list. + * + * \note This operation leaves \p elm in an invalid state. + * + * \param elm Link of the containing struct to remove from the list + * + * \memberof wl_list + */ void wl_list_remove(struct wl_list *elm); +/** + * Determines the length of the list. + * + * \note This is an O(n) operation. + * + * \param list List whose length is to be determined + * + * \return Number of elements in the list + * + * \memberof wl_list + */ int wl_list_length(const struct wl_list *list); +/** + * Determines if the list is empty. + * + * \param list List whose emptiness is to be determined + * + * \return 1 if empty, or 0 if not empty + * + * \memberof wl_list + */ int wl_list_empty(const struct wl_list *list); +/** + * Inserts all of the elements of one list into another, after the element + * represented by \p list. + * + * \note This leaves \p other in an invalid state. + * + * \param list List element after which the other list elements will be inserted + * \param other List of elements to insert + * + * \memberof wl_list + */ void wl_list_insert_list(struct wl_list *list, struct wl_list *other); /** - * Retrieves a pointer to the containing struct of a given member item. + * Retrieves a pointer to a containing struct, given a member name. * - * This macro allows conversion from a pointer to a item to its containing + * This macro allows "conversion" from a pointer to a member to its containing * struct. This is useful if you have a contained item like a wl_list, - * wl_listener, or wl_signal, provided via a callback or other means and would + * wl_listener, or wl_signal, provided via a callback or other means, and would * like to retrieve the struct that contains it. * * To demonstrate, the following example retrieves a pointer to @@ -152,41 +229,82 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other); * * \code * struct example_container { - * struct wl_listener destroy_listener; - * // other members... + * struct wl_listener destroy_listener; + * // other members... * }; * * void example_container_destroy(struct wl_listener *listener, void *data) * { - * struct example_container *ctr; + * struct example_container *ctr; * - * ctr = wl_container_of(listener, ctr, destroy_listener); - * // destroy ctr... + * ctr = wl_container_of(listener, ctr, destroy_listener); + * // destroy ctr... * } * \endcode * - * \param ptr A valid pointer to the contained item. + * \note `sample` need not be a valid pointer. A null or uninitialised pointer + * is sufficient. * - * \param sample A pointer to the type of content that the list item - * stores. Sample does not need be a valid pointer; a null or - * an uninitialised pointer will suffice. + * \param ptr Valid pointer to the contained member + * \param sample Pointer to a struct whose type contains \p ptr + * \param member Named location of \p ptr within the \p sample type * - * \param member The named location of ptr within the sample type. - * - * \return The container for the specified pointer. + * \return The container for the specified pointer */ #define wl_container_of(ptr, sample, member) \ (__typeof__(sample))((char *)(ptr) - \ offsetof(__typeof__(*sample), member)) -/* If the above macro causes problems on your compiler you might be - * able to find an alternative name for the non-standard __typeof__ - * operator and add a special case here */ +/** + * Iterates over a list. + * + * This macro expresses a for-each iterator for wl_list. Given a list and + * wl_list link member name (often named `link` by convention), this macro + * assigns each element in the list to \p pos, which can then be referenced in + * a trailing code block. For example, given a wl_list of `struct message` + * elements: + * + * \code + * struct message { + * char *contents; + * wl_list link; + * }; + * + * struct wl_list *message_list; + * // Assume message_list now "contains" many messages + * + * struct message *m; + * wl_list_for_each(m, message_list, link) { + * do_something_with_message(m); + * } + * \endcode + * + * \param pos Cursor that each list element will be assigned to + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ #define wl_list_for_each(pos, head, member) \ for (pos = wl_container_of((head)->next, pos, member); \ &pos->member != (head); \ pos = wl_container_of(pos->member.next, pos, member)) +/** + * Iterates over a list, safe against removal of the list element. + * + * \note Only removal of the current element, \p pos, is safe. Removing + * any other element during traversal may lead to a loop malfunction. + * + * \sa wl_list_for_each() + * + * \param pos Cursor that each list element will be assigned to + * \param tmp Temporary pointer of the same type as \p pos + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ #define wl_list_for_each_safe(pos, tmp, head, member) \ for (pos = wl_container_of((head)->next, pos, member), \ tmp = wl_container_of((pos)->member.next, tmp, member); \ @@ -194,11 +312,37 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other); pos = tmp, \ tmp = wl_container_of(pos->member.next, tmp, member)) +/** + * Iterates backwards over a list. + * + * \sa wl_list_for_each() + * + * \param pos Cursor that each list element will be assigned to + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ #define wl_list_for_each_reverse(pos, head, member) \ for (pos = wl_container_of((head)->prev, pos, member); \ &pos->member != (head); \ pos = wl_container_of(pos->member.prev, pos, member)) +/** + * Iterates backwards over a list, safe against removal of the list element. + * + * \note Only removal of the current element, \p pos, is safe. Removing + * any other element during traversal may lead to a loop malfunction. + * + * \sa wl_list_for_each() + * + * \param pos Cursor that each list element will be assigned to + * \param tmp Temporary pointer of the same type as \p pos + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ #define wl_list_for_each_reverse_safe(pos, tmp, head, member) \ for (pos = wl_container_of((head)->prev, pos, member), \ tmp = wl_container_of((pos)->member.prev, tmp, member); \ From db61796026e0b1a2a649ad1369521ebfe2adc074 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 27 Sep 2016 13:03:47 -0500 Subject: [PATCH 0371/1152] util: Document wl_array Add doxygen comments for wl_array and its methods. Signed-off-by: Yong Bakos Reviewed-by: Eric Engestrom Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 87 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index a4043901..9b7a4b9f 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -350,29 +350,92 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other); pos = tmp, \ tmp = wl_container_of(pos->member.prev, tmp, member)) +/** + * \class wl_array + * + * Dynamic array + * + * A wl_array is a dynamic array that can only grow until released. It is + * intended for relatively small allocations whose size is variable or not known + * in advance. While construction of a wl_array does not require all elements to + * be of the same size, wl_array_for_each() does require all elements to have + * the same type and size. + * + */ struct wl_array { size_t size; size_t alloc; void *data; }; +/** + * Initializes the array. + * + * \param array Array to initialize + * + * \memberof wl_array + */ +void +wl_array_init(struct wl_array *array); + +/** + * Releases the array data. + * + * \note Leaves the array in an invalid state. + * + * \param array Array whose data is to be released + * + * \memberof wl_array + */ +void +wl_array_release(struct wl_array *array); + +/** + * Increases the size of the array by \p size bytes. + * + * \param array Array whose size is to be increased + * \param size Number of bytes to increase the size of the array by + * + * \return A pointer to the beginning of the newly appended space, or NULL when + * resizing fails. + * + * \memberof wl_array + */ +void * +wl_array_add(struct wl_array *array, size_t size); + +/** + * Copies the contents of \p source to \p array. + * + * \param array Destination array to copy to + * \param source Source array to copy from + * + * \return 0 on success, or -1 on failure + * + * \memberof wl_array + */ +int +wl_array_copy(struct wl_array *array, struct wl_array *source); + +/** + * Iterates over an array. + * + * This macro expresses a for-each iterator for wl_array. It assigns each + * element in the array to \p pos, which can then be referenced in a trailing + * code block. \p pos must be a pointer to the array element type, and all + * array elements must be of the same type and size. + * + * \param pos Cursor that each array element will be assigned to + * \param array Array to iterate over + * + * \relates wl_array + * \sa wl_list_for_each() + */ #define wl_array_for_each(pos, array) \ for (pos = (array)->data; \ (const char *) pos < ((const char *) (array)->data + (array)->size); \ (pos)++) -void -wl_array_init(struct wl_array *array); - -void -wl_array_release(struct wl_array *array); - -void * -wl_array_add(struct wl_array *array, size_t size); - -int -wl_array_copy(struct wl_array *array, struct wl_array *source); - typedef int32_t wl_fixed_t; static inline double From e8ad23266f36521215dcd7cfcc524e0ef67d66dd Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 27 Sep 2016 13:03:48 -0500 Subject: [PATCH 0372/1152] wl_array: Set data to invalid address after free Explicitly set the data member to an invalid memory address during wl_array_release, such that re-using a freed wl_array without re-initializing causes a crash. In addition, this pointer assignment makes wl_array_release testable. Define a constant for the invalid memory address, and add documentation about this behavior, starting at libwayland version 1.13. See https://lists.freedesktop.org/archives/wayland-devel/2016-September/031116.html Signed-off-by: Yong Bakos Reviewed-by: Eric Engestrom [Pekka: remove the doc about crashing] Signed-off-by: Pekka Paalanen --- src/wayland-private.h | 3 +++ src/wayland-util.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/wayland-private.h b/src/wayland-private.h index ac712d93..ef58ccfe 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -36,6 +36,9 @@ #include "wayland-util.h" +/* Invalid memory address */ +#define WL_ARRAY_POISON_PTR (void *) 4 + #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define container_of(ptr, type, member) ({ \ diff --git a/src/wayland-util.c b/src/wayland-util.c index 639ccf87..077fec75 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -102,6 +102,7 @@ WL_EXPORT void wl_array_release(struct wl_array *array) { free(array->data); + array->data = WL_ARRAY_POISON_PTR; } WL_EXPORT void * From f04f2187810fc8dcda92305df76fb54a255c20f9 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 27 Sep 2016 13:03:49 -0500 Subject: [PATCH 0373/1152] tests: Test wl_array_release array-test.c did not cover wl_array_release, so add one test that specifically tests this method. Signed-off-by: Yong Bakos Reviewed-by: Eric Engestrom [Pekka: do not overwrite array.data] Signed-off-by: Pekka Paalanen --- tests/array-test.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/array-test.c b/tests/array-test.c index fe53240e..fe589f42 100644 --- a/tests/array-test.c +++ b/tests/array-test.c @@ -45,6 +45,20 @@ TEST(array_init) } } +TEST(array_release) +{ + struct wl_array array; + void *ptr; + + wl_array_init(&array); + ptr = wl_array_add(&array, 1); + assert(ptr != NULL); + assert(array.data != NULL); + + wl_array_release(&array); + assert(array.data == WL_ARRAY_POISON_PTR); +} + TEST(array_add) { struct mydata { From a1ab2c03ae7471895f8d24f9186c5ac288545e7f Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 27 Sep 2016 13:03:50 -0500 Subject: [PATCH 0374/1152] array-test: Include wayland-util.h and simplify init test Include wayland-util.h in addition to wayland-private.h, to be more explicit about where wl_array is defined. Remove the useless repeated testing of wl_array_init, because if it fails once out of thousands of iterations we're all doomed anyway. Signed-off-by: Yong Bakos Reviewed-by: Eric Engestrom [Pekka: add the memset] Signed-off-by: Pekka Paalanen --- tests/array-test.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/array-test.c b/tests/array-test.c index fe589f42..eda610b5 100644 --- a/tests/array-test.c +++ b/tests/array-test.c @@ -25,24 +25,22 @@ #include #include +#include +#include "wayland-util.h" #include "wayland-private.h" #include "test-runner.h" TEST(array_init) { - const int iterations = 4122; /* this is arbitrary */ - int i; + struct wl_array array; - /* Init array an arbitray amount of times and verify the - * defaults are sensible. */ + /* fill with garbage to emulate uninitialized memory */ + memset(&array, 0x57, sizeof array); - for (i = 0; i < iterations; i++) { - struct wl_array array; - wl_array_init(&array); - assert(array.size == 0); - assert(array.alloc == 0); - assert(array.data == 0); - } + wl_array_init(&array); + assert(array.size == 0); + assert(array.alloc == 0); + assert(array.data == 0); } TEST(array_release) From ae139d8b6bc36fdc657369ed25dc331df967e35e Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sat, 17 Sep 2016 15:04:32 -0700 Subject: [PATCH 0375/1152] util: Document GCC attributes Add doxygen comment blocks so these annotations are documented in the html documentation. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 9b7a4b9f..7b280d19 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -40,21 +40,28 @@ extern "C" { #endif -/* GCC visibility */ +/** Visibility attribute */ #if defined(__GNUC__) && __GNUC__ >= 4 #define WL_EXPORT __attribute__ ((visibility("default"))) #else #define WL_EXPORT #endif -/* Deprecated attribute */ +/** Deprecated attribute */ #if defined(__GNUC__) && __GNUC__ >= 4 #define WL_DEPRECATED __attribute__ ((deprecated)) #else #define WL_DEPRECATED #endif -/* Printf annotation */ +/** + * Printf-style argument attribute + * + * \param x Ordinality of the format string argument + * \param y Ordinality of the argument to check against the format string + * + * \sa https://gcc.gnu.org/onlinedocs/gcc-3.2.1/gcc/Function-Attributes.html + */ #if defined(__GNUC__) && __GNUC__ >= 4 #define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y))) #else From da58e07c3d30978470a4bb7332277c9e6fdf401f Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Fri, 12 Aug 2016 12:04:41 -0700 Subject: [PATCH 0376/1152] shm: Make shm_pool_interface static const Add static const modifiers to the shm_pool_interface definition, making it consistent with the other wl_*_interface definitions and mundanely safer. Note that this does not affect the ABI, according to abi-dumper and abi-compliance-checker[1]; and weston and its shm-backed clients still run as expected. [1]: http://lvc.github.io/abi-compliance-checker/ Signed-off-by: Yong Bakos Tested-by: Yong Bakos Acked-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 7fea364c..8e2ef77d 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -247,7 +247,7 @@ shm_pool_resize(struct wl_client *client, struct wl_resource *resource, shm_pool_finish_resize(pool); } -struct wl_shm_pool_interface shm_pool_interface = { +static const struct wl_shm_pool_interface shm_pool_interface = { shm_pool_create_buffer, shm_pool_destroy, shm_pool_resize From 9e2e3bcaa74806ae6dd9fec7f9505b1605e5965b Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Thu, 29 Sep 2016 23:59:58 -0700 Subject: [PATCH 0377/1152] protocol: Describe wl_registry as singleton Other singleton objects in the protocol are described as such. Add a singleton adjective to the wl_registry description, making it similar to other descriptions. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 6c6d078a..c5aaf5ce 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -104,8 +104,8 @@ - The global registry object. The server has a number of global - objects that are available to all clients. These objects + The singleton global registry object. The server has a number of + global objects that are available to all clients. These objects typically represent an actual object in the server (for example, an input device) or they are singleton objects that provide extension functionality. From b802108f6e8dc664a36cc0b1f707d130e48221aa Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sun, 2 Oct 2016 09:09:59 -0700 Subject: [PATCH 0378/1152] protocol: Use singleton global consistently The protocol describes wl_shm as a "global singleton" rather than "singleton global," which is the order used throughout other protocol object descriptions. Re-order the terms for consistency. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index c5aaf5ce..aa07f45b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -259,7 +259,7 @@ - A global singleton object that provides support for shared + A singleton global object that provides support for shared memory. Clients can create wl_shm_pool objects using the create_pool From 23d3c67c9a1ccc74f4e0359b06d56db3c1a65861 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 10 Nov 2016 11:14:03 +0000 Subject: [PATCH 0379/1152] tests: Use unique XDG_RUNTIME_DIR Rather than using a hardcoded 'wayland-tests' directory under the existing XDG_RUNTIME_DIR to use as the new runtime dir, use mkdtemp to guarantee uniqueness. This fixes make -jN check, as well as just happening to run 'make check' twice from the same session. Signed-off-by: Daniel Stone Reported-by: Pekka Paalanen Reviewed-by: Pekka Paalanen Tested-by: Pekka Paalanen --- tests/test-runner.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test-runner.c b/tests/test-runner.c index 4aa6667a..82a0a7b8 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -226,10 +226,11 @@ set_xdg_runtime_dir(void) xrd_env = getenv("XDG_RUNTIME_DIR"); /* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */ - assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests", + assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests-XXXXXX", xrd_env ? xrd_env : "/tmp") < PATH_MAX) && "test error: XDG_RUNTIME_DIR too long"); + assert(mkdtemp(xdg_runtime_dir) && "test error: mkdtemp failed"); if (mkdir(xdg_runtime_dir, 0700) == -1) if (errno != EEXIST) { perror("Creating XDG_RUNTIME_DIR"); From ed7a6880256847e1febbae613e5dbd369e3afbea Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Wed, 7 Sep 2016 06:25:27 -0700 Subject: [PATCH 0380/1152] scanner: Remove return doxygen annotation Replace \returns with just Returns, as this is not a doxygen comment block. (Avoids differing with the existing convention of \return for return values.) Signed-off-by: Yong Bakos Reviewed-by: Bryce Harrington Reviewed-by: Pekka Paalanen --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index c9272759..3f181cda 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -586,7 +586,7 @@ free_interface(struct interface *interface) * * Upon error, this routine does not modify or set errno. * - * \returns -1 on error, or a non-negative integer on success + * Returns -1 on error, or a non-negative integer on success */ static int strtouint(const char *str) From a6cf19842cc3773c0167e0cf1477295f23de9dd9 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Thu, 27 Oct 2016 08:55:01 -0700 Subject: [PATCH 0381/1152] util: Document wl_message Signed-off-by: Yong Bakos Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/wayland-util.h b/src/wayland-util.h index 7b280d19..4dba1ed5 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -68,9 +68,77 @@ extern "C" { #define WL_PRINTF(x, y) #endif +/** + * Protocol message signature + * + * A wl_message describes the signature of an actual protocol message, such as a + * request or event, that adheres to the Wayland protocol wire format. The + * protocol implementation uses a wl_message within its demarshal machinery for + * decoding messages between a compositor and its clients. In a sense, a + * wl_message is to a protocol message like a class is to an object. + * + * The `name` of a wl_message is the name of the corresponding protocol message. + * The `signature` is an ordered list of symbols representing the data types + * of message arguments and, optionally, a protocol version and indicators for + * nullability. A leading integer in the `signature` indicates the _since_ + * version of the protocol message. A `?` preceding a data type symbol indicates + * that the following argument type is nullable. When no arguments accompany a + * message, `signature` is an empty string. + * + * * `i`: int + * * `u`: uint + * * `f`: fixed + * * `s`: string + * * `o`: object + * * `n`: new_id + * * `a`: array + * * `h`: fd + * * `?`: following argument is nullable + * + * While demarshaling primitive arguments is straightforward, when demarshaling + * messages containing `object` or `new_id` arguments, the protocol + * implementation often must determine the type of the object. The `types` of a + * wl_message is an array of wl_interface references that correspond to `o` and + * `n` arguments in `signature`, with `NULL` placeholders for arguments with + * non-object types. + * + * Consider the protocol event wl_display `delete_id` that has a single `uint` + * argument. The wl_message is: + * + * \code + * { "delete_id", "u", [NULL] } + * \endcode + * + * Here, the message `name` is `"delete_id"`, the `signature` is `"u"`, and the + * argument `types` is `[NULL]`, indicating that the `uint` argument has no + * corresponding wl_interface since it is a primitive argument. + * + * In contrast, consider a `wl_foo` interface supporting protocol request `bar` + * that has existed since version 2, and has two arguments: a `uint` and an + * object of type `wl_baz_interface` that may be `NULL`. Such a `wl_message` + * might be: + * + * \code + * { "bar", "2u?o", [NULL, &wl_baz_interface] } + * \endcode + * + * Here, the message `name` is `"bar"`, and the `signature` is `"2u?o"`. Notice + * how the `2` indicates the protocol version, the `u` indicates the first + * argument type is `uint`, and the `?o` indicates that the second argument + * is an object that may be `NULL`. Lastly, the argument `types` array indicates + * that no wl_interface corresponds to the first argument, while the type + * `wl_baz_interface` corresponds to the second argument. + * + * \sa wl_argument + * \sa wl_interface + * \sa Wire Format + */ struct wl_message { + /** Message name */ const char *name; + /** Message signature */ const char *signature; + /** Object argument interfaces */ const struct wl_interface **types; }; From 66a26aeb2a4d76141938aab72113259c19e7ea17 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Mon, 31 Oct 2016 06:46:18 -0700 Subject: [PATCH 0382/1152] protocol: Remove inconsistent line breaks Enum entries and message arguments are sometimes preceded by a blank line, but often aren't. Standardize the format of the protocol specification by removing blank lines preceding a list of message arguments and enum entries. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index aa07f45b..909dabd1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -226,7 +226,6 @@ so it is valid to destroy the pool immediately after creating a buffer from it. - @@ -252,7 +251,6 @@ created, but using the new size. This request can only be used to make the pool bigger. - @@ -359,7 +357,6 @@ objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool. - @@ -449,7 +446,6 @@ wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback. - @@ -487,7 +483,6 @@ Sent immediately after creating the wl_data_offer object. One event per offered mime type. - @@ -635,7 +630,6 @@ Used for feedback during drag-and-drop. - @@ -645,7 +639,6 @@ specified mime type over the passed file descriptor, then close it. - @@ -823,7 +816,6 @@ object will send out data_offer.offer events to describe the mime types it offers. - @@ -834,7 +826,6 @@ enter time is provided by the x and y arguments, in surface-local coordinates. - @@ -1090,7 +1081,6 @@ The flags argument controls details of the transient behaviour. - @@ -1173,7 +1163,6 @@ corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. - @@ -1260,7 +1249,6 @@ The width and height arguments specify the size of the window in surface-local coordinates. - @@ -1374,7 +1362,6 @@ If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. - @@ -1405,7 +1392,6 @@ which uses buffer coordinates instead of surface coordinates, and is probably the preferred and intuitive way of doing this. - @@ -1447,7 +1433,6 @@ The callback_data passed in the callback is the current time, in milliseconds, with an undefined base. - @@ -1478,7 +1463,6 @@ destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty. - @@ -1508,7 +1492,6 @@ immediately. A NULL wl_region causes the input region to be set to infinite. - @@ -1661,7 +1644,6 @@ two requests separately and only transform from one to the other after receiving the wl_surface.commit. - @@ -1828,7 +1810,6 @@ cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. - @@ -1845,7 +1826,6 @@ is undefined and a client should respond to this event by setting an appropriate pointer image with the set_cursor request. - @@ -1870,7 +1850,6 @@ surface_x and surface_y are the location relative to the focused surface. - @@ -1894,7 +1873,6 @@ The time argument is a timestamp with millisecond granularity, with an undefined base. - @@ -1928,7 +1906,6 @@ When applicable, a client can transform its content relative to the scroll distance. - @@ -2155,7 +2132,6 @@ The time argument is a timestamp with millisecond granularity, with an undefined base. - @@ -2167,7 +2143,6 @@ Notifies clients that the modifier and/or group state has changed, and it should update its local state. - @@ -2198,7 +2173,6 @@ so clients should continue listening for the event past the creation of wl_keyboard. - - @@ -2447,7 +2420,6 @@ Add the specified rectangle to the region. - @@ -2458,7 +2430,6 @@ Subtract the specified rectangle from the region. - @@ -2512,7 +2483,6 @@ must not have an existing wl_subsurface object. Otherwise a protocol error is raised. - - @@ -2632,7 +2601,6 @@ A new sub-surface is initially added as the top-most in the stack of its siblings and parent. - @@ -2642,7 +2610,6 @@ The sub-surface is placed just below the reference surface. See wl_subsurface.place_above. - From 9618087c6ad0b1e2de4037279f7370846c5f508c Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Thu, 3 Nov 2016 13:42:54 -0700 Subject: [PATCH 0383/1152] tests: Test wl_message_count_arrays message-test.c did not cover wl_message_count_arrays, so add one test that specifically tests this method. Note that this exposes wl_message_count_arrays in a private header (wayland-private.h), and removes the `static` modifier of the implementation. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- src/connection.c | 2 +- src/wayland-private.h | 3 +++ tests/message-test.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index c3293a9f..5c3d187c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -392,7 +392,7 @@ wl_connection_queue(struct wl_connection *connection, return wl_buffer_put(&connection->out, data, count); } -static int +int wl_message_count_arrays(const struct wl_message *message) { int i, arrays; diff --git a/src/wayland-private.h b/src/wayland-private.h index ef58ccfe..676b1813 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -162,6 +162,9 @@ get_next_argument(const char *signature, struct argument_details *details); int arg_count_for_signature(const char *signature); +int +wl_message_count_arrays(const struct wl_message *message); + int wl_message_get_since(const struct wl_message *message); diff --git a/tests/message-test.c b/tests/message-test.c index cb08f90c..389f788b 100644 --- a/tests/message-test.c +++ b/tests/message-test.c @@ -51,3 +51,40 @@ TEST(message_version) messages[i].expected_version); } } + +TEST(message_count_arrays) +{ + unsigned int i; + struct wl_message fake_messages[] = { + { "empty", "", NULL }, + { "non_present", "iufsonh", NULL }, + { "leading", "aiufsonh", NULL}, + { "trailing", "iufsonha", NULL }, + { "middle", "iufasonh", NULL }, + { "multiple", "aaiufaasonhaa", NULL }, + { "leading_version", "2aaiufaasonhaa", NULL }, + { "among_nullables", "iufsa?oa?nah", NULL }, + { "all_mixed", "2aiufas?oa?na", NULL }, + }; + const struct { + const struct wl_message *message; + int expected_array_count; + } messages[] = { + { &wl_pointer_interface.events[WL_POINTER_ENTER], 0 }, + { &wl_keyboard_interface.events[WL_KEYBOARD_ENTER], 1 }, + { &fake_messages[0], 0 }, + { &fake_messages[1], 0 }, + { &fake_messages[2], 1 }, + { &fake_messages[3], 1 }, + { &fake_messages[4], 1 }, + { &fake_messages[5], 6 }, + { &fake_messages[6], 6 }, + { &fake_messages[7], 3 }, + { &fake_messages[8], 4 } + }; + + for (i = 0; i < ARRAY_LENGTH(messages); ++i) { + assert(wl_message_count_arrays(messages[i].message) == + messages[i].expected_array_count); + } +} From edd62e62b77061ed09c34bf9e964ddcc6c08c88e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 9 Nov 2016 17:16:51 +0200 Subject: [PATCH 0384/1152] Makefile: do not put TESTS into check_PROGRAMS If you assign TESTS into check_PROGRAMS, you cannot add a test that is not built from source files. Instead, use a temporary variable built_test_programs to hold the names that are both programs built from source files and tests to execute. This change is required by the following patch adding wayland-scanner test script. Signed-off-by: Pekka Paalanen Reviewed-by: Emilio Pozuelo Monfort Reviewed-by: Peter Hutterer --- Makefile.am | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3eb6fd53..d35231cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -144,7 +144,7 @@ libwayland_cursor_la_CFLAGS = \ -DICONDIR=\"$(ICONDIR)\" -TESTS = \ +built_test_programs = \ array-test \ client-test \ display-test \ @@ -165,11 +165,13 @@ TESTS = \ protocol-logger-test if ENABLE_CPP_TEST -TESTS += cpp-compile-test +built_test_programs += cpp-compile-test endif +TESTS = $(built_test_programs) + check_PROGRAMS = \ - $(TESTS) \ + $(built_test_programs) \ exec-fd-leak-checker noinst_PROGRAMS = \ From 2c6350beb92816eb9213c4944d197485e788ef6d Mon Sep 17 00:00:00 2001 From: Bill Spitzak Date: Mon, 16 May 2016 23:18:06 -0700 Subject: [PATCH 0385/1152] scanner: Fixed doxygen group name for _add_listener Signed-off-by: Bill Spitzak Acked-by: Yong Bakos --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 3f181cda..a239c711 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1362,7 +1362,7 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid if (side == CLIENT) { printf("/**\n" - " * @ingroup %s_iface\n" + " * @ingroup iface_%s\n" " */\n", interface->name); printf("static inline int\n" "%s_add_listener(struct %s *%s,\n" From 2281bc08b2be2eb07c169fc283dc1e16f99bf346 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 8 Nov 2016 08:02:12 -0800 Subject: [PATCH 0386/1152] util: Remove stray space from function signature wl_fixed_to_double had a stray space before the parameter list. Remove this space. Signed-off-by: Yong Bakos Reviewed-by: Daniel Stone --- src/wayland-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 4dba1ed5..53f480ba 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -514,7 +514,7 @@ wl_array_copy(struct wl_array *array, struct wl_array *source); typedef int32_t wl_fixed_t; static inline double -wl_fixed_to_double (wl_fixed_t f) +wl_fixed_to_double(wl_fixed_t f) { union { double d; From fd75029fb9e0c5678914f5046809ab047cf7583c Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Fri, 11 Nov 2016 07:55:38 -0800 Subject: [PATCH 0387/1152] util: Document wl_fixed_t Add doxygen comments for wl_fixed_t and its methods. Although wl_fixed_t can be thought of as an opaque struct, it is a typedef. As such, doxygen does not provide an elegant means of documenting it as both a 'class' with members and as a typedef. In other words, documenting it as a class gives us a nice doxygen page for wl_fixed_t and its related methods, but this leaves the typedef documentation blank in the documentation for wayland-util, and does not provide a link to the documentation for wl_fixed_t. Hence, this patch does not treat wl_fixed_t as a class/struct, resulting in the typedef being documented and keeping the functions listed in wayland-util, rather than a separate unlinked page devoted to just wl_fixed_t. Signed-off-by: Yong Bakos Reviewed-by: Peter Hutterer Reviewed-by: Daniel Stone --- src/wayland-util.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/wayland-util.h b/src/wayland-util.h index 53f480ba..50f3372a 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -511,8 +511,23 @@ wl_array_copy(struct wl_array *array, struct wl_array *source); (const char *) pos < ((const char *) (array)->data + (array)->size); \ (pos)++) +/** + * Fixed-point number + * + * A `wl_fixed_t` is a 24.8 signed fixed-point number with a sign bit, 23 bits + * of integer precision and 8 bits of decimal precision. Consider `wl_fixed_t` + * as an opaque struct with methods that facilitate conversion to and from + * `double` and `int` types. + */ typedef int32_t wl_fixed_t; +/** + * Converts a fixed-point number to a floating-point number. + * + * \param f Fixed-point number to convert + * + * \return Floating-point representation of the fixed-point argument + */ static inline double wl_fixed_to_double(wl_fixed_t f) { @@ -526,6 +541,13 @@ wl_fixed_to_double(wl_fixed_t f) return u.d - (3LL << 43); } +/** + * Converts a floating-point number to a fixed-point number. + * + * \param d Floating-point number to convert + * + * \return Fixed-point representation of the floating-point argument + */ static inline wl_fixed_t wl_fixed_from_double(double d) { @@ -539,12 +561,26 @@ wl_fixed_from_double(double d) return u.i; } +/** + * Converts a fixed-point number to an integer. + * + * \param f Fixed-point number to convert + * + * \return Integer component of the fixed-point argument + */ static inline int wl_fixed_to_int(wl_fixed_t f) { return f / 256; } +/** + * Converts an integer to a fixed-point number. + * + * \param i Integer to convert + * + * \return Fixed-point representation of the integer argument + */ static inline wl_fixed_t wl_fixed_from_int(int i) { From 6a18a87727c64719c68168568b9ab1e4d7c2d9c1 Mon Sep 17 00:00:00 2001 From: Dennis Kempin Date: Fri, 11 Nov 2016 11:40:55 -0800 Subject: [PATCH 0388/1152] protocol: Extend wl_touch with touchpoint shape and orientation This CL updates the wl_touch interface with a shape and orientation event. The shape/orientation of a touch point is not relevant for most UI applications, but allows a better experience in some cases such as drawing apps. The events are used by the compositor to inform the client about changes in the shape and orientation of a touchpoint, which is approximated by an ellipse and it's angle to the y-axis. The event is optional and only sent when compositor and the touch device support this type of information. The client is responsible for making a reasonable assumption about the touch shape if no shape is reported. Signed-off-by: Dennis Kempin Reviewed-by: Peter Hutterer Reviewed-by: Yong Bakos Reviewed-by: Daniel Stone --- protocol/wayland.xml | 82 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 909dabd1..8311a18d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1651,7 +1651,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -1760,7 +1760,7 @@ - + The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -2069,7 +2069,7 @@ - + The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -2180,7 +2180,7 @@ - + The wl_touch interface represents a touchscreen associated with a seat. @@ -2230,7 +2230,14 @@ - Indicates the end of a contact point list. + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. + + A wl_touch.frame terminates at least one event but otherwise no + guarantee is provided about the set of events within a frame. A client + must assume that any state not updated in a frame is unchanged from the + previously known state. @@ -2250,6 +2257,71 @@ + + + + + + Sent when a touchpoint has changed its shape. + + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. + + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.orientation may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.shape event for this touch ID but both events may occur within + the same wl_touch.frame. + + A touchpoint shape is approximated by an ellipse through the major and + minor axis length. The major axis length describes the longer diameter + of the ellipse, while the minor axis length describes the shorter + diameter. Major and minor are orthogonal and both are specified in + surface-local coordinates. The center of the ellipse is always at the + touchpoint location as reported by wl_touch.down or wl_touch.move. + + This event is only sent by the compositor if the touch device supports + shape reports. The client has to make reasonable assumptions about the + shape if it did not receive this event. + + + + + + + + + Sent when a touchpoint has changed its orientation. + + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. + + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.shape may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.orientation event for this touch ID but both events may occur + within the same wl_touch.frame. + + The orientation describes the clockwise angle of a touchpoint's major + axis to the positive surface y-axis and is normalized to the -180 to + +180 degree range. The granularity of orientation depends on the touch + device, some devices only support binary rotation values between 0 and + 90 degrees. + + This event is only sent by the compositor if the touch device supports + orientation reports. + + + + From 06b7c471b7de2e0d9852af60514594417b29d4e3 Mon Sep 17 00:00:00 2001 From: Moritz Kiefer Date: Sun, 6 Nov 2016 18:35:19 +0100 Subject: [PATCH 0389/1152] doc: Fix a typo in the client documentation Signed-off-by: Moritz Kiefer Reviewed-by: Yong Bakos --- doc/publican/sources/Client.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/sources/Client.xml b/doc/publican/sources/Client.xml index fcdd2f2f..19bf3e95 100644 --- a/doc/publican/sources/Client.xml +++ b/doc/publican/sources/Client.xml @@ -30,7 +30,7 @@ object created. - Though some conveinence functions are provided, libwayland-client + Though some convenience functions are provided, libwayland-client is designed to allow the calling code to wait for events, so that different polling mechanisms can be used. A file descriptor is provided, when it becomes ready for reading the calling code can From aa51a833eb9b3d8fb58a64ff685b249d65ec35b5 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 16 Nov 2016 13:42:21 +0200 Subject: [PATCH 0390/1152] Makefile: build also test programs during a normal build Put also test programs into noinst_PROGRAMS so that they get always built. In check_PROGRAMS they are built for 'make check' but not for 'make'. This makes it harder to accidentally break the test programs. v2: also change check_LTLIBRARIES to noinst_LTLIBRARIES Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone --- Makefile.am | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index d35231cd..eea5aaef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -170,14 +170,12 @@ endif TESTS = $(built_test_programs) -check_PROGRAMS = \ - $(built_test_programs) \ - exec-fd-leak-checker - noinst_PROGRAMS = \ + $(built_test_programs) \ + exec-fd-leak-checker \ fixed-benchmark -check_LTLIBRARIES = libtest-runner.la +noinst_LTLIBRARIES += libtest-runner.la libtest_runner_la_SOURCES = \ tests/test-runner.c \ From 0cdc3229b02ffa1863f48e21806f6a070937fb0b Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sun, 6 Nov 2016 18:25:37 -0800 Subject: [PATCH 0391/1152] util: Document wl_interface Add doxygen comments for wl_interface. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/wayland-util.h b/src/wayland-util.h index 50f3372a..5e9c4111 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -142,12 +142,64 @@ struct wl_message { const struct wl_interface **types; }; +/** + * Protocol object interface + * + * A wl_interface describes the API of a protocol object defined in the Wayland + * protocol specification. The protocol implementation uses a wl_interface + * within its marshalling machinery for encoding client requests. + * + * The `name` of a wl_interface is the name of the corresponding protocol + * interface, and `version` represents the version of the interface. The members + * `method_count` and `event_count` represent the number of `methods` (requests) + * and `events` in the respective wl_message members. + * + * For example, consider a protocol interface `foo`, marked as version `1`, with + * two requests and one event. + * + * \code + * + * + * + * + * + * \endcode + * + * Given two wl_message arrays `foo_requests` and `foo_events`, a wl_interface + * for `foo` might be: + * + * \code + * struct wl_interface foo_interface = { + * "foo", 1, + * 2, foo_requests, + * 1, foo_events + * }; + * \endcode + * + * \note The server side of the protocol may define interface implementation + * types that incorporate the term `interface` in their name. Take + * care to not confuse these server-side `struct`s with a wl_interface + * variable whose name also ends in `interface`. For example, while the + * server may define a type `struct wl_foo_interface`, the client may + * define a `struct wl_interface wl_foo_interface`. + * + * \sa wl_message + * \sa wl_proxy + * \sa Interfaces + * \sa Versioning + */ struct wl_interface { + /** Interface name */ const char *name; + /** Interface version */ int version; + /** Number of methods (requests) */ int method_count; + /** Method (request) signatures */ const struct wl_message *methods; + /** Number of events */ int event_count; + /** Event signatures */ const struct wl_message *events; }; From b0cd65deacb99c9cf0ca5c0c741307eb1f4a9c5e Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 8 Nov 2016 07:56:30 -0800 Subject: [PATCH 0392/1152] tests: Test wl_interface_equal The test suite did not cover wl_interface_equal, so add one test that specifically tests this method. Add the new test to Makefile.am. Signed-off-by: Yong Bakos [Pekka: add assert(&wl_registry_interface != ©);] Signed-off-by: Pekka Paalanen --- Makefile.am | 3 +++ tests/interface-test.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/interface-test.c diff --git a/Makefile.am b/Makefile.am index eea5aaef..87bab0da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -151,6 +151,7 @@ built_test_programs = \ connection-test \ event-loop-test \ fixed-test \ + interface-test \ list-test \ map-test \ os-wrappers-test \ @@ -203,6 +204,8 @@ event_loop_test_SOURCES = tests/event-loop-test.c event_loop_test_LDADD = libtest-runner.la fixed_test_SOURCES = tests/fixed-test.c fixed_test_LDADD = libtest-runner.la +interface_test_SOURCES = tests/interface-test.c +interface_test_LDADD = libtest-runner.la list_test_SOURCES = tests/list-test.c list_test_LDADD = libtest-runner.la map_test_SOURCES = tests/map-test.c diff --git a/tests/interface-test.c b/tests/interface-test.c new file mode 100644 index 00000000..5290bb65 --- /dev/null +++ b/tests/interface-test.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2016 Yong Bakos + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "wayland-client.h" +#include "wayland-private.h" +#include "test-runner.h" + +TEST(interface_equal) +{ + const struct wl_interface fake = { + "fake", 1, 0, NULL, 0, NULL + }; + const struct wl_interface fake_registry = { + "wl_registry", 1, 0, NULL, 0, NULL + }; + const struct wl_interface copy = wl_registry_interface; + + assert(&wl_registry_interface != ©); + + assert(wl_interface_equal(&wl_registry_interface, + &wl_registry_interface)); + assert(wl_interface_equal(&wl_registry_interface, ©)); + assert(wl_interface_equal(&wl_registry_interface, + &fake_registry)); + assert(!wl_interface_equal(&wl_registry_interface, &fake)); +} From 2d328a4559152ed11e52bdbd85689d7b2239596a Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Fri, 11 Nov 2016 07:08:09 -0800 Subject: [PATCH 0393/1152] tests: Add nullable check to wl_message_count_arrays Array argument symbols in a wl_message may be nullable, but the test for wl_message_count_arrays did not test this. Add one more wl_message with nullable array arguments. Signed-off-by: Yong Bakos Reviewed-by: Pekka Paalanen --- tests/message-test.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/message-test.c b/tests/message-test.c index 389f788b..4e693923 100644 --- a/tests/message-test.c +++ b/tests/message-test.c @@ -64,7 +64,8 @@ TEST(message_count_arrays) { "multiple", "aaiufaasonhaa", NULL }, { "leading_version", "2aaiufaasonhaa", NULL }, { "among_nullables", "iufsa?oa?nah", NULL }, - { "all_mixed", "2aiufas?oa?na", NULL }, + { "nullable", "?aiufs?a?onh?a", NULL }, + { "all_mixed", "2?aiufas?oa?na", NULL }, }; const struct { const struct wl_message *message; @@ -80,7 +81,8 @@ TEST(message_count_arrays) { &fake_messages[5], 6 }, { &fake_messages[6], 6 }, { &fake_messages[7], 3 }, - { &fake_messages[8], 4 } + { &fake_messages[8], 3 }, + { &fake_messages[9], 4 }, }; for (i = 0; i < ARRAY_LENGTH(messages); ++i) { From 9ac70f4349bfa4f934b96cdff4eaa88d5811b5a5 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sat, 12 Nov 2016 10:11:21 -0800 Subject: [PATCH 0394/1152] util: Improve documentation of wl_argument Standardize the doxygen comment format, add clarity to the writing, decouple the description from specifics of usage, add see-also's, and massage the union member type comments. Signed-off-by: Yong Bakos Reviewed-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 5e9c4111..8b02ff0e 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -640,22 +640,25 @@ wl_fixed_from_int(int i) } /** - * \brief A union representing all of the basic data types that can be passed - * along the wayland wire format. + * Protocol message argument data types * - * This union represents all of the basic data types that can be passed in the - * wayland wire format. It is used by dispatchers and runtime-friendly - * versions of the event and request marshaling functions. + * This union represents all of the argument types in the Wayland protocol wire + * format. The protocol implementation uses wl_argument within its marshalling + * machinery for dispatching messages between a client and a compositor. + * + * \sa wl_message + * \sa wl_interface + * \sa Wire Format */ union wl_argument { - int32_t i; /**< signed integer */ - uint32_t u; /**< unsigned integer */ - wl_fixed_t f; /**< fixed point */ - const char *s; /**< string */ - struct wl_object *o; /**< object */ - uint32_t n; /**< new_id */ - struct wl_array *a; /**< array */ - int32_t h; /**< file descriptor */ + int32_t i; /**< `int` */ + uint32_t u; /**< `uint` */ + wl_fixed_t f; /**< `fixed` */ + const char *s; /**< `string` */ + struct wl_object *o; /**< `object` */ + uint32_t n; /**< `new_id` */ + struct wl_array *a; /**< `array` */ + int32_t h; /**< `fd` */ }; /** From 5c48aac33b191b30f36e777be836441e211166b6 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 27 Jul 2016 11:06:24 -0500 Subject: [PATCH 0395/1152] cursor: Remove "weston" from anonymous shm filenames This mildly confused me during some debugging, so I guess it wouldn't hurt to make the filename more indicative of where it was actually created. Signed-off-by: Derek Foreman Reviewed-by: Yong Bakos Reviewed-by: Giulio Camuffo Reviewed-by: Daniel Stone --- cursor/os-compatibility.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index d7d4b33b..e972d219 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -103,7 +103,7 @@ create_tmpfile_cloexec(char *tmpname) int os_create_anonymous_file(off_t size) { - static const char template[] = "/weston-shared-XXXXXX"; + static const char template[] = "/wayland-cursor-shared-XXXXXX"; const char *path; char *name; int fd; From b4636b5e606177c5a771fcf4349fbf321fdf071c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 18 Nov 2016 12:35:27 +1000 Subject: [PATCH 0396/1152] protocol: spell out that we're using linux/input-event-codes.h button codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because we already rely on it in the callers anyway. This is a retrofit, which is not ideal but I'm not sure any compositor out there uses anything else. Might as well define it. Signed-off-by: Peter Hutterer Reviewed-by: Jonas Ådahl Reviewed-by: Daniel Stone --- protocol/wayland.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8311a18d..c5163749 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1872,6 +1872,14 @@ enter event. The time argument is a timestamp with millisecond granularity, with an undefined base. + + The button is a button code as defined in the Linux kernel's + linux/input-event-codes.h header file, e.g. BTN_LEFT. + + Any 16-bit button code value is reserved for future additions to the + kernel's event code list. All other button codes above 0xFFFF are + currently undefined but may be used in future versions of this + protocol. From 013cfd9408ca7460f62dd1721a057330bd6524a8 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sun, 20 Nov 2016 09:26:08 -0800 Subject: [PATCH 0397/1152] util: Improve documentation of wl_iterator_result Use declarative voice, remove the unnecessary doxygen \enum tag, and add two see-also's. This keeps the output the same but makes the comment voice consistent, a little more readable, and refers to documented functions that use this enum type. Signed-off-by: Yong Bakos Reviewed-by: Peter Hutterer --- src/wayland-util.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 8b02ff0e..2fd99a03 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -684,9 +684,11 @@ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0); -/** \enum wl_iterator_result +/** + * Return value of an iterator function * - * This enum represents the return value of an iterator function. + * \sa wl_client_for_each_resource_iterator_func_t + * \sa wl_client_for_each_resource */ enum wl_iterator_result { /** Stop the iteration */ From 8d335bf264ee388034d9ac505daef0ea72d9f214 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 26 Aug 2016 16:04:03 -0500 Subject: [PATCH 0398/1152] build: Fix scanner path in uninstalled pkg-config file this was generating a pkg-config file that said wayland-scanner was wayland/src/wayland-scanner when it's actually wayland/wayland-scanner Signed-off-by: Derek Foreman Acked-by: Bryce Harrington Reviewed-by: Daniel Stone --- src/wayland-scanner-uninstalled.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-scanner-uninstalled.pc.in b/src/wayland-scanner-uninstalled.pc.in index 8dcfef31..132f42d0 100644 --- a/src/wayland-scanner-uninstalled.pc.in +++ b/src/wayland-scanner-uninstalled.pc.in @@ -1,5 +1,5 @@ pkgdatadir=@abs_top_srcdir@ -wayland_scanner=@abs_builddir@/wayland-scanner +wayland_scanner=@abs_top_builddir@/wayland-scanner Name: Wayland Scanner Description: Wayland scanner (not installed) From 84776648a55558a59913fb0b0b4b76229fb89a8e Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 26 Aug 2016 16:04:02 -0500 Subject: [PATCH 0399/1152] buildsystem: adjust uninstalled -client/server pkg-config infra Add missing protocol dir to uninstalled include path. Signed-off-by: Reynaldo H. Verdejo Pinochet Reviewed-by: Derek Foreman Signed-off-by: Derek Foreman Acked-by: Bryce Harrington Signed-off-by: Daniel Stone --- src/wayland-client-uninstalled.pc.in | 3 ++- src/wayland-server-uninstalled.pc.in | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wayland-client-uninstalled.pc.in b/src/wayland-client-uninstalled.pc.in index 3086621d..732736e9 100644 --- a/src/wayland-client-uninstalled.pc.in +++ b/src/wayland-client-uninstalled.pc.in @@ -1,8 +1,9 @@ libdir=@abs_builddir@/.libs includedir=@abs_srcdir@ +protocoldir=@abs_top_builddir@/protocol Name: Wayland Client Description: Wayland client side library (not installed) Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} +Cflags: -I${includedir} -I${protocoldir} Libs: -L${libdir} -lwayland-client diff --git a/src/wayland-server-uninstalled.pc.in b/src/wayland-server-uninstalled.pc.in index 90577828..562686c3 100644 --- a/src/wayland-server-uninstalled.pc.in +++ b/src/wayland-server-uninstalled.pc.in @@ -1,8 +1,9 @@ libdir=@abs_builddir@/.libs includedir=@abs_srcdir@ +protocoldir=@abs_top_builddir@/protocol Name: Wayland Server Description: Server side implementation of the Wayland protocol (not installed) Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} +Cflags: -I${includedir} -I${protocoldir} Libs: -L${libdir} -lwayland-server From b05baa6aa82ba434229ed37a64c0022d56ebf46d Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Sun, 20 Nov 2016 08:59:15 -0800 Subject: [PATCH 0400/1152] util: Document wl_log_func_t Add a doxygen comment for wl_log_func_t. Signed-off-by: Yong Bakos Reviewed-by: Daniel Stone --- src/wayland-util.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/wayland-util.h b/src/wayland-util.h index 2fd99a03..170bf865 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -682,6 +682,30 @@ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *); +/** + * Log function type alias + * + * The C implementation of the Wayland protocol abstracts the details of + * logging. Users may customize the logging behavior, with a function conforming + * to the `wl_log_func_t` type, via `wl_log_set_handler_client` and + * `wl_log_set_handler_server`. + * + * A `wl_log_func_t` must conform to the expectations of `vprintf`, and + * expects two arguments: a string to write and a corresponding variable + * argument list. While the string to write may contain format specifiers and + * use values in the variable argument list, the behavior of any `wl_log_func_t` + * depends on the implementation. + * + * \note Take care to not confuse this with `wl_protocol_logger_func_t`, which + * is a specific server-side logger for requests and events. + * + * \param "const char *" String to write to the log, containing optional format + * specifiers + * \param "va_list" Variable argument list + * + * \sa wl_log_set_handler_client + * \sa wl_log_set_handler_server + */ typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0); /** From a2cbdefc92ad012435e7e2d63ecb93243b445fc0 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 8 Jul 2016 16:42:30 -0700 Subject: [PATCH 0401/1152] wayland-client: Require base 10 for WAYLAND_SOCKET, explicitly The third arg to strtol() specifies the base to assume for the number. When 0 is passed, as is currently done in wayland-client.c, hexadecimal and octal numbers are permitted and automatically detected and converted. I can find no indication that we would ever expect use of hexadecimal or octal for socket fd's. So be explicit about what base we're assuming here and avoid any potential surprises. Signed-off-by: Bryce Harrington Reviewed-by: Yong Bakos Reviewed-by: Daniel Stone --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 03c087a6..3d7361ea 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1006,7 +1006,7 @@ wl_display_connect(const char *name) if (connection) { int prev_errno = errno; errno = 0; - fd = strtol(connection, &end, 0); + fd = strtol(connection, &end, 10); if (errno != 0 || connection == end || *end != '\0') return NULL; errno = prev_errno; From a26ed0949ec21a26fbbb6fb02f775e2da45611ea Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 21 Nov 2016 11:43:22 +0000 Subject: [PATCH 0402/1152] protocol: indentation fixes 8 spaces changed to one tab Signed-off-by: Peter Hutterer Reviewed-by: Daniel Stone Acked-by: Bryce Harrington --- protocol/wayland.xml | 100 +++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index c5163749..098f286b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -129,7 +129,7 @@ Binds a new, client-created object to the server using the - specified name as the identifier. + specified name as the identifier. @@ -139,9 +139,9 @@ Notify the client of global objects. - The event notifies the client that a global object with - the given name is now available, and it implements the - given version of the given interface. + The event notifies the client that a global object with + the given name is now available, and it implements the + given version of the given interface. @@ -152,10 +152,10 @@ Notify the client of removed global objects. - This event notifies the client that the global identified - by name is no longer available. If the client bound to - the global using the bind request, the client should now - destroy that object. + This event notifies the client that the global identified + by name is no longer available. If the client bound to + the global using the bind request, the client should now + destroy that object. The object remains valid and requests to the object will be ignored until the client destroys it, to avoid races between @@ -355,7 +355,7 @@ The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file - descriptor, to use as backing memory for the pool. + descriptor, to use as backing memory for the pool. @@ -915,14 +915,14 @@ - Create a new data source. + Create a new data source. - Create a new data device for a given seat. + Create a new data device for a given seat. @@ -1308,7 +1308,7 @@ - These errors can be emitted in response to wl_surface requests. + These errors can be emitted in response to wl_surface requests. @@ -1661,8 +1661,8 @@ - This is a bitmask of capabilities this seat has; if a member is - set, then it is present on the seat. + This is a bitmask of capabilities this seat has; if a member is + set, then it is present on the seat. @@ -1857,7 +1857,7 @@ - Describes the physical state of a button that produced the button + Describes the physical state of a button that produced the button event. @@ -1870,8 +1870,8 @@ The location of the click is given by the last motion or enter event. - The time argument is a timestamp with millisecond - granularity, with an undefined base. + The time argument is a timestamp with millisecond + granularity, with an undefined base. The button is a button code as defined in the Linux kernel's linux/input-event-codes.h header file, e.g. BTN_LEFT. @@ -2091,7 +2091,7 @@ + summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/> @@ -2137,8 +2137,8 @@ A key was pressed or released. - The time argument is a timestamp with millisecond - granularity, with an undefined base. + The time argument is a timestamp with millisecond + granularity, with an undefined base. @@ -2168,23 +2168,23 @@ - Informs the client about the keyboard's repeat rate and delay. + Informs the client about the keyboard's repeat rate and delay. - This event is sent as soon as the wl_keyboard object has been created, - and is guaranteed to be received by the client before any key press - event. + This event is sent as soon as the wl_keyboard object has been created, + and is guaranteed to be received by the client before any key press + event. - Negative values for either rate or delay are illegal. A rate of zero - will disable any repeating (regardless of the value of delay). + Negative values for either rate or delay are illegal. A rate of zero + will disable any repeating (regardless of the value of delay). - This event can be sent later on as well with a new value if necessary, - so clients should continue listening for the event past the creation - of wl_keyboard. + This event can be sent later on as well with a new value if necessary, + so clients should continue listening for the event past the creation + of wl_keyboard. + summary="the rate of repeating keys in characters per second"/> + summary="delay in milliseconds since key down until repeating starts"/> @@ -2425,10 +2425,10 @@ mode that was received with the current flag set. The size of a mode is given in physical hardware units of - the output device. This is not necessarily the same as - the output size in the global compositor space. For instance, - the output may be scaled, as described in wl_output.scale, - or transformed, as described in wl_output.transform. + the output device. This is not necessarily the same as + the output size in the global compositor space. For instance, + the output may be scaled, as described in wl_output.scale, + or transformed, as described in wl_output.transform. @@ -2440,20 +2440,20 @@ - This event is sent after all other properties have been - sent after binding to the output object and after any - other property changes done after that. This allows - changes to the output properties to be seen as - atomic, even if they happen via multiple events. + This event is sent after all other properties have been + sent after binding to the output object and after any + other property changes done after that. This allows + changes to the output properties to be seen as + atomic, even if they happen via multiple events. This event contains scaling geometry information - that is not in the geometry event. It may be sent after - binding the output object or if the output scale changes - later. If it is not sent, the client should assume a + that is not in the geometry event. It may be sent after + binding the output object or if the output scale changes + later. If it is not sent, the client should assume a scale of 1. A scale larger than 1 means that the compositor will @@ -2550,7 +2550,7 @@ + summary="the to-be sub-surface is invalid"/> @@ -2564,11 +2564,11 @@ error is raised. + summary="the new sub-surface object ID"/> + summary="the surface to be turned into a sub-surface"/> + summary="the parent surface"/> @@ -2637,7 +2637,7 @@ + summary="wl_surface is not a sibling or the parent"/> @@ -2682,7 +2682,7 @@ of its siblings and parent. + summary="the reference surface"/> @@ -2691,7 +2691,7 @@ See wl_subsurface.place_above. + summary="the reference surface"/> From 024200745fc83373effdf64f3a5684c1a9cd9a13 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Mon, 21 Nov 2016 05:44:44 -0800 Subject: [PATCH 0403/1152] util: Clarify documentation of wl_dispatcher_func_t Adjust the brief, clarify the behavior and arguments, correct a grammar error, document the parameters, and document the return type. Signed-off-by: Yong Bakos Reviewed-by: Bryce Harrington Reviewed-by: Daniel Stone --- src/wayland-util.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 170bf865..f0a45088 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -662,21 +662,28 @@ union wl_argument { }; /** - * \brief A function pointer type for a dispatcher. + * Dispatcher function type alias * * A dispatcher is a function that handles the emitting of callbacks in client - * code. For programs directly using the C library, this is done by using - * libffi to call function pointers. When binding to languages other than C, + * code. For programs directly using the C library, this is done by using + * libffi to call function pointers. When binding to languages other than C, * dispatchers provide a way to abstract the function calling process to be * friendlier to other function calling systems. * - * A dispatcher takes five arguments: The first is the dispatcher-specific - * implementation data associated with the target object. The second is the - * object on which the callback is being invoked (either wl_proxy or - * wl_resource). The third and fourth arguments are the opcode the wl_message - * structure corresponding to the callback being emitted. The final argument - * is an array of arguments received from the other process via the wire - * protocol. + * A dispatcher takes five arguments: The first is the dispatcher-specific + * implementation associated with the target object. The second is the object + * upon which the callback is being invoked (either wl_proxy or wl_resource). + * The third and fourth arguments are the opcode and the wl_message + * corresponding to the callback. The final argument is an array of arguments + * received from the other process via the wire protocol. + * + * \param "const void *" Dispatcher-specific implementation data + * \param "void *" Callback invocation target (wl_proxy or `wl_resource`) + * \param uint32_t Callback opcode + * \param "const struct wl_message *" Callback message signature + * \param "union wl_argument *" Array of received arguments + * + * \return 0 on success, or -1 on failure */ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, const struct wl_message *, From 992b451dc44389e56913e3e57681aec00ee6bffc Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 4 Oct 2016 17:26:40 +0300 Subject: [PATCH 0404/1152] tests: add data files for future wayland-scanner test This patch adds the input and reference output data files for the wayland-scanner tests to be added by the following patch. The data files are split into their own patch because they are extremely uninteresting to review: - example.xml is just a copy wayland.xml from 1.12.0 - small.xml is a tiny dummy definition used for testing scanner variations without causing lots of big output files - the other files are wayland-scanner products from the xml files Signed-off-by: Pekka Paalanen Reviewed-by: Emilio Pozuelo Monfort v2: update output due to 2c6350beb92816eb9213c4944d197485e788ef6d Acked-by: Yong Bakos --- tests/data/example-client.h | 5477 ++++++++++++++++++++++++++++++++ tests/data/example-code.c | 505 +++ tests/data/example-server.h | 4285 +++++++++++++++++++++++++ tests/data/example.xml | 2693 ++++++++++++++++ tests/data/small-client-core.h | 172 + tests/data/small-client.h | 172 + tests/data/small-code-core.c | 61 + tests/data/small-code.c | 61 + tests/data/small-server-core.h | 131 + tests/data/small-server.h | 131 + tests/data/small.xml | 52 + 11 files changed, 13740 insertions(+) create mode 100644 tests/data/example-client.h create mode 100644 tests/data/example-code.c create mode 100644 tests/data/example-server.h create mode 100644 tests/data/example.xml create mode 100644 tests/data/small-client-core.h create mode 100644 tests/data/small-client.h create mode 100644 tests/data/small-code-core.c create mode 100644 tests/data/small-code.c create mode 100644 tests/data/small-server-core.h create mode 100644 tests/data/small-server.h create mode 100644 tests/data/small.xml diff --git a/tests/data/example-client.h b/tests/data/example-client.h new file mode 100644 index 00000000..b2bb24e5 --- /dev/null +++ b/tests/data/example-client.h @@ -0,0 +1,5477 @@ +/* SCANNER TEST */ + +#ifndef WAYLAND_CLIENT_PROTOCOL_H +#define WAYLAND_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_wayland The wayland protocol + * @section page_ifaces_wayland Interfaces + * - @subpage page_iface_wl_display - core global object + * - @subpage page_iface_wl_registry - global registry object + * - @subpage page_iface_wl_callback - callback object + * - @subpage page_iface_wl_compositor - the compositor singleton + * - @subpage page_iface_wl_shm_pool - a shared memory pool + * - @subpage page_iface_wl_shm - shared memory support + * - @subpage page_iface_wl_buffer - content for a wl_surface + * - @subpage page_iface_wl_data_offer - offer to transfer data + * - @subpage page_iface_wl_data_source - offer to transfer data + * - @subpage page_iface_wl_data_device - data transfer device + * - @subpage page_iface_wl_data_device_manager - data transfer interface + * - @subpage page_iface_wl_shell - create desktop-style surfaces + * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface + * - @subpage page_iface_wl_surface - an onscreen surface + * - @subpage page_iface_wl_seat - group of input devices + * - @subpage page_iface_wl_pointer - pointer input device + * - @subpage page_iface_wl_keyboard - keyboard input device + * - @subpage page_iface_wl_touch - touchscreen input device + * - @subpage page_iface_wl_output - compositor output region + * - @subpage page_iface_wl_region - region interface + * - @subpage page_iface_wl_subcompositor - sub-surface compositing + * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface + * @section page_copyright_wayland Copyright + *
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct wl_buffer; +struct wl_callback; +struct wl_compositor; +struct wl_data_device; +struct wl_data_device_manager; +struct wl_data_offer; +struct wl_data_source; +struct wl_display; +struct wl_keyboard; +struct wl_output; +struct wl_pointer; +struct wl_region; +struct wl_registry; +struct wl_seat; +struct wl_shell; +struct wl_shell_surface; +struct wl_shm; +struct wl_shm_pool; +struct wl_subcompositor; +struct wl_subsurface; +struct wl_surface; +struct wl_touch; + +/** + * @page page_iface_wl_display wl_display + * @section page_iface_wl_display_desc Description + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + * @section page_iface_wl_display_api API + * See @ref iface_wl_display. + */ +/** + * @defgroup iface_wl_display The wl_display interface + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + */ +extern const struct wl_interface wl_display_interface; +/** + * @page page_iface_wl_registry wl_registry + * @section page_iface_wl_registry_desc Description + * + * The global registry object. The server has a number of global + * objects that are available to all clients. These objects + * typically represent an actual object in the server (for example, + * an input device) or they are singleton objects that provide + * extension functionality. + * + * When a client creates a registry object, the registry object + * will emit a global event for each global currently in the + * registry. Globals come and go as a result of device or + * monitor hotplugs, reconfiguration or other events, and the + * registry will send out global and global_remove events to + * keep the client up to date with the changes. To mark the end + * of the initial burst of events, the client can use the + * wl_display.sync request immediately after calling + * wl_display.get_registry. + * + * A client can bind to a global object by using the bind + * request. This creates a client-side handle that lets the object + * emit events to the client and lets the client invoke requests on + * the object. + * @section page_iface_wl_registry_api API + * See @ref iface_wl_registry. + */ +/** + * @defgroup iface_wl_registry The wl_registry interface + * + * The global registry object. The server has a number of global + * objects that are available to all clients. These objects + * typically represent an actual object in the server (for example, + * an input device) or they are singleton objects that provide + * extension functionality. + * + * When a client creates a registry object, the registry object + * will emit a global event for each global currently in the + * registry. Globals come and go as a result of device or + * monitor hotplugs, reconfiguration or other events, and the + * registry will send out global and global_remove events to + * keep the client up to date with the changes. To mark the end + * of the initial burst of events, the client can use the + * wl_display.sync request immediately after calling + * wl_display.get_registry. + * + * A client can bind to a global object by using the bind + * request. This creates a client-side handle that lets the object + * emit events to the client and lets the client invoke requests on + * the object. + */ +extern const struct wl_interface wl_registry_interface; +/** + * @page page_iface_wl_callback wl_callback + * @section page_iface_wl_callback_desc Description + * + * Clients can handle the 'done' event to get notified when + * the related request is done. + * @section page_iface_wl_callback_api API + * See @ref iface_wl_callback. + */ +/** + * @defgroup iface_wl_callback The wl_callback interface + * + * Clients can handle the 'done' event to get notified when + * the related request is done. + */ +extern const struct wl_interface wl_callback_interface; +/** + * @page page_iface_wl_compositor wl_compositor + * @section page_iface_wl_compositor_desc Description + * + * A compositor. This object is a singleton global. The + * compositor is in charge of combining the contents of multiple + * surfaces into one displayable output. + * @section page_iface_wl_compositor_api API + * See @ref iface_wl_compositor. + */ +/** + * @defgroup iface_wl_compositor The wl_compositor interface + * + * A compositor. This object is a singleton global. The + * compositor is in charge of combining the contents of multiple + * surfaces into one displayable output. + */ +extern const struct wl_interface wl_compositor_interface; +/** + * @page page_iface_wl_shm_pool wl_shm_pool + * @section page_iface_wl_shm_pool_desc Description + * + * The wl_shm_pool object encapsulates a piece of memory shared + * between the compositor and client. Through the wl_shm_pool + * object, the client can allocate shared memory wl_buffer objects. + * All objects created through the same pool share the same + * underlying mapped memory. Reusing the mapped memory avoids the + * setup/teardown overhead and is useful when interactively resizing + * a surface or for many small buffers. + * @section page_iface_wl_shm_pool_api API + * See @ref iface_wl_shm_pool. + */ +/** + * @defgroup iface_wl_shm_pool The wl_shm_pool interface + * + * The wl_shm_pool object encapsulates a piece of memory shared + * between the compositor and client. Through the wl_shm_pool + * object, the client can allocate shared memory wl_buffer objects. + * All objects created through the same pool share the same + * underlying mapped memory. Reusing the mapped memory avoids the + * setup/teardown overhead and is useful when interactively resizing + * a surface or for many small buffers. + */ +extern const struct wl_interface wl_shm_pool_interface; +/** + * @page page_iface_wl_shm wl_shm + * @section page_iface_wl_shm_desc Description + * + * A global singleton object that provides support for shared + * memory. + * + * Clients can create wl_shm_pool objects using the create_pool + * request. + * + * At connection setup time, the wl_shm object emits one or more + * format events to inform clients about the valid pixel formats + * that can be used for buffers. + * @section page_iface_wl_shm_api API + * See @ref iface_wl_shm. + */ +/** + * @defgroup iface_wl_shm The wl_shm interface + * + * A global singleton object that provides support for shared + * memory. + * + * Clients can create wl_shm_pool objects using the create_pool + * request. + * + * At connection setup time, the wl_shm object emits one or more + * format events to inform clients about the valid pixel formats + * that can be used for buffers. + */ +extern const struct wl_interface wl_shm_interface; +/** + * @page page_iface_wl_buffer wl_buffer + * @section page_iface_wl_buffer_desc Description + * + * A buffer provides the content for a wl_surface. Buffers are + * created through factory interfaces such as wl_drm, wl_shm or + * similar. It has a width and a height and can be attached to a + * wl_surface, but the mechanism by which a client provides and + * updates the contents is defined by the buffer factory interface. + * @section page_iface_wl_buffer_api API + * See @ref iface_wl_buffer. + */ +/** + * @defgroup iface_wl_buffer The wl_buffer interface + * + * A buffer provides the content for a wl_surface. Buffers are + * created through factory interfaces such as wl_drm, wl_shm or + * similar. It has a width and a height and can be attached to a + * wl_surface, but the mechanism by which a client provides and + * updates the contents is defined by the buffer factory interface. + */ +extern const struct wl_interface wl_buffer_interface; +/** + * @page page_iface_wl_data_offer wl_data_offer + * @section page_iface_wl_data_offer_desc Description + * + * A wl_data_offer represents a piece of data offered for transfer + * by another client (the source client). It is used by the + * copy-and-paste and drag-and-drop mechanisms. The offer + * describes the different mime types that the data can be + * converted to and provides the mechanism for transferring the + * data directly from the source client. + * @section page_iface_wl_data_offer_api API + * See @ref iface_wl_data_offer. + */ +/** + * @defgroup iface_wl_data_offer The wl_data_offer interface + * + * A wl_data_offer represents a piece of data offered for transfer + * by another client (the source client). It is used by the + * copy-and-paste and drag-and-drop mechanisms. The offer + * describes the different mime types that the data can be + * converted to and provides the mechanism for transferring the + * data directly from the source client. + */ +extern const struct wl_interface wl_data_offer_interface; +/** + * @page page_iface_wl_data_source wl_data_source + * @section page_iface_wl_data_source_desc Description + * + * The wl_data_source object is the source side of a wl_data_offer. + * It is created by the source client in a data transfer and + * provides a way to describe the offered data and a way to respond + * to requests to transfer the data. + * @section page_iface_wl_data_source_api API + * See @ref iface_wl_data_source. + */ +/** + * @defgroup iface_wl_data_source The wl_data_source interface + * + * The wl_data_source object is the source side of a wl_data_offer. + * It is created by the source client in a data transfer and + * provides a way to describe the offered data and a way to respond + * to requests to transfer the data. + */ +extern const struct wl_interface wl_data_source_interface; +/** + * @page page_iface_wl_data_device wl_data_device + * @section page_iface_wl_data_device_desc Description + * + * There is one wl_data_device per seat which can be obtained + * from the global wl_data_device_manager singleton. + * + * A wl_data_device provides access to inter-client data transfer + * mechanisms such as copy-and-paste and drag-and-drop. + * @section page_iface_wl_data_device_api API + * See @ref iface_wl_data_device. + */ +/** + * @defgroup iface_wl_data_device The wl_data_device interface + * + * There is one wl_data_device per seat which can be obtained + * from the global wl_data_device_manager singleton. + * + * A wl_data_device provides access to inter-client data transfer + * mechanisms such as copy-and-paste and drag-and-drop. + */ +extern const struct wl_interface wl_data_device_interface; +/** + * @page page_iface_wl_data_device_manager wl_data_device_manager + * @section page_iface_wl_data_device_manager_desc Description + * + * The wl_data_device_manager is a singleton global object that + * provides access to inter-client data transfer mechanisms such as + * copy-and-paste and drag-and-drop. These mechanisms are tied to + * a wl_seat and this interface lets a client get a wl_data_device + * corresponding to a wl_seat. + * + * Depending on the version bound, the objects created from the bound + * wl_data_device_manager object will have different requirements for + * functioning properly. See wl_data_source.set_actions, + * wl_data_offer.accept and wl_data_offer.finish for details. + * @section page_iface_wl_data_device_manager_api API + * See @ref iface_wl_data_device_manager. + */ +/** + * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface + * + * The wl_data_device_manager is a singleton global object that + * provides access to inter-client data transfer mechanisms such as + * copy-and-paste and drag-and-drop. These mechanisms are tied to + * a wl_seat and this interface lets a client get a wl_data_device + * corresponding to a wl_seat. + * + * Depending on the version bound, the objects created from the bound + * wl_data_device_manager object will have different requirements for + * functioning properly. See wl_data_source.set_actions, + * wl_data_offer.accept and wl_data_offer.finish for details. + */ +extern const struct wl_interface wl_data_device_manager_interface; +/** + * @page page_iface_wl_shell wl_shell + * @section page_iface_wl_shell_desc Description + * + * This interface is implemented by servers that provide + * desktop-style user interfaces. + * + * It allows clients to associate a wl_shell_surface with + * a basic surface. + * @section page_iface_wl_shell_api API + * See @ref iface_wl_shell. + */ +/** + * @defgroup iface_wl_shell The wl_shell interface + * + * This interface is implemented by servers that provide + * desktop-style user interfaces. + * + * It allows clients to associate a wl_shell_surface with + * a basic surface. + */ +extern const struct wl_interface wl_shell_interface; +/** + * @page page_iface_wl_shell_surface wl_shell_surface + * @section page_iface_wl_shell_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like toplevel, fullscreen + * or popup windows, move, resize or maximize them, associate + * metadata like title and class, etc. + * + * On the server side the object is automatically destroyed when + * the related wl_surface is destroyed. On the client side, + * wl_shell_surface_destroy() must be called before destroying + * the wl_surface object. + * @section page_iface_wl_shell_surface_api API + * See @ref iface_wl_shell_surface. + */ +/** + * @defgroup iface_wl_shell_surface The wl_shell_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like toplevel, fullscreen + * or popup windows, move, resize or maximize them, associate + * metadata like title and class, etc. + * + * On the server side the object is automatically destroyed when + * the related wl_surface is destroyed. On the client side, + * wl_shell_surface_destroy() must be called before destroying + * the wl_surface object. + */ +extern const struct wl_interface wl_shell_surface_interface; +/** + * @page page_iface_wl_surface wl_surface + * @section page_iface_wl_surface_desc Description + * + * A surface is a rectangular area that is displayed on the screen. + * It has a location, size and pixel contents. + * + * The size of a surface (and relative positions on it) is described + * in surface-local coordinates, which may differ from the buffer + * coordinates of the pixel content, in case a buffer_transform + * or a buffer_scale is used. + * + * A surface without a "role" is fairly useless: a compositor does + * not know where, when or how to present it. The role is the + * purpose of a wl_surface. Examples of roles are a cursor for a + * pointer (as set by wl_pointer.set_cursor), a drag icon + * (wl_data_device.start_drag), a sub-surface + * (wl_subcompositor.get_subsurface), and a window as defined by a + * shell protocol (e.g. wl_shell.get_shell_surface). + * + * A surface can have only one role at a time. Initially a + * wl_surface does not have a role. Once a wl_surface is given a + * role, it is set permanently for the whole lifetime of the + * wl_surface object. Giving the current role again is allowed, + * unless explicitly forbidden by the relevant interface + * specification. + * + * Surface roles are given by requests in other interfaces such as + * wl_pointer.set_cursor. The request should explicitly mention + * that this request gives a role to a wl_surface. Often, this + * request also creates a new protocol object that represents the + * role and adds additional functionality to wl_surface. When a + * client wants to destroy a wl_surface, they must destroy this 'role + * object' before the wl_surface. + * + * Destroying the role object does not remove the role from the + * wl_surface, but it may stop the wl_surface from "playing the role". + * For instance, if a wl_subsurface object is destroyed, the wl_surface + * it was created for will be unmapped and forget its position and + * z-order. It is allowed to create a wl_subsurface for the same + * wl_surface again, but it is not allowed to use the wl_surface as + * a cursor (cursor is a different role than sub-surface, and role + * switching is not allowed). + * @section page_iface_wl_surface_api API + * See @ref iface_wl_surface. + */ +/** + * @defgroup iface_wl_surface The wl_surface interface + * + * A surface is a rectangular area that is displayed on the screen. + * It has a location, size and pixel contents. + * + * The size of a surface (and relative positions on it) is described + * in surface-local coordinates, which may differ from the buffer + * coordinates of the pixel content, in case a buffer_transform + * or a buffer_scale is used. + * + * A surface without a "role" is fairly useless: a compositor does + * not know where, when or how to present it. The role is the + * purpose of a wl_surface. Examples of roles are a cursor for a + * pointer (as set by wl_pointer.set_cursor), a drag icon + * (wl_data_device.start_drag), a sub-surface + * (wl_subcompositor.get_subsurface), and a window as defined by a + * shell protocol (e.g. wl_shell.get_shell_surface). + * + * A surface can have only one role at a time. Initially a + * wl_surface does not have a role. Once a wl_surface is given a + * role, it is set permanently for the whole lifetime of the + * wl_surface object. Giving the current role again is allowed, + * unless explicitly forbidden by the relevant interface + * specification. + * + * Surface roles are given by requests in other interfaces such as + * wl_pointer.set_cursor. The request should explicitly mention + * that this request gives a role to a wl_surface. Often, this + * request also creates a new protocol object that represents the + * role and adds additional functionality to wl_surface. When a + * client wants to destroy a wl_surface, they must destroy this 'role + * object' before the wl_surface. + * + * Destroying the role object does not remove the role from the + * wl_surface, but it may stop the wl_surface from "playing the role". + * For instance, if a wl_subsurface object is destroyed, the wl_surface + * it was created for will be unmapped and forget its position and + * z-order. It is allowed to create a wl_subsurface for the same + * wl_surface again, but it is not allowed to use the wl_surface as + * a cursor (cursor is a different role than sub-surface, and role + * switching is not allowed). + */ +extern const struct wl_interface wl_surface_interface; +/** + * @page page_iface_wl_seat wl_seat + * @section page_iface_wl_seat_desc Description + * + * A seat is a group of keyboards, pointer and touch devices. This + * object is published as a global during start up, or when such a + * device is hot plugged. A seat typically has a pointer and + * maintains a keyboard focus and a pointer focus. + * @section page_iface_wl_seat_api API + * See @ref iface_wl_seat. + */ +/** + * @defgroup iface_wl_seat The wl_seat interface + * + * A seat is a group of keyboards, pointer and touch devices. This + * object is published as a global during start up, or when such a + * device is hot plugged. A seat typically has a pointer and + * maintains a keyboard focus and a pointer focus. + */ +extern const struct wl_interface wl_seat_interface; +/** + * @page page_iface_wl_pointer wl_pointer + * @section page_iface_wl_pointer_desc Description + * + * The wl_pointer interface represents one or more input devices, + * such as mice, which control the pointer location and pointer_focus + * of a seat. + * + * The wl_pointer interface generates motion, enter and leave + * events for the surfaces that the pointer is located over, + * and button and axis events for button presses, button releases + * and scrolling. + * @section page_iface_wl_pointer_api API + * See @ref iface_wl_pointer. + */ +/** + * @defgroup iface_wl_pointer The wl_pointer interface + * + * The wl_pointer interface represents one or more input devices, + * such as mice, which control the pointer location and pointer_focus + * of a seat. + * + * The wl_pointer interface generates motion, enter and leave + * events for the surfaces that the pointer is located over, + * and button and axis events for button presses, button releases + * and scrolling. + */ +extern const struct wl_interface wl_pointer_interface; +/** + * @page page_iface_wl_keyboard wl_keyboard + * @section page_iface_wl_keyboard_desc Description + * + * The wl_keyboard interface represents one or more keyboards + * associated with a seat. + * @section page_iface_wl_keyboard_api API + * See @ref iface_wl_keyboard. + */ +/** + * @defgroup iface_wl_keyboard The wl_keyboard interface + * + * The wl_keyboard interface represents one or more keyboards + * associated with a seat. + */ +extern const struct wl_interface wl_keyboard_interface; +/** + * @page page_iface_wl_touch wl_touch + * @section page_iface_wl_touch_desc Description + * + * The wl_touch interface represents a touchscreen + * associated with a seat. + * + * Touch interactions can consist of one or more contacts. + * For each contact, a series of events is generated, starting + * with a down event, followed by zero or more motion events, + * and ending with an up event. Events relating to the same + * contact point can be identified by the ID of the sequence. + * @section page_iface_wl_touch_api API + * See @ref iface_wl_touch. + */ +/** + * @defgroup iface_wl_touch The wl_touch interface + * + * The wl_touch interface represents a touchscreen + * associated with a seat. + * + * Touch interactions can consist of one or more contacts. + * For each contact, a series of events is generated, starting + * with a down event, followed by zero or more motion events, + * and ending with an up event. Events relating to the same + * contact point can be identified by the ID of the sequence. + */ +extern const struct wl_interface wl_touch_interface; +/** + * @page page_iface_wl_output wl_output + * @section page_iface_wl_output_desc Description + * + * An output describes part of the compositor geometry. The + * compositor works in the 'compositor coordinate system' and an + * output corresponds to a rectangular area in that space that is + * actually visible. This typically corresponds to a monitor that + * displays part of the compositor space. This object is published + * as global during start up, or when a monitor is hotplugged. + * @section page_iface_wl_output_api API + * See @ref iface_wl_output. + */ +/** + * @defgroup iface_wl_output The wl_output interface + * + * An output describes part of the compositor geometry. The + * compositor works in the 'compositor coordinate system' and an + * output corresponds to a rectangular area in that space that is + * actually visible. This typically corresponds to a monitor that + * displays part of the compositor space. This object is published + * as global during start up, or when a monitor is hotplugged. + */ +extern const struct wl_interface wl_output_interface; +/** + * @page page_iface_wl_region wl_region + * @section page_iface_wl_region_desc Description + * + * A region object describes an area. + * + * Region objects are used to describe the opaque and input + * regions of a surface. + * @section page_iface_wl_region_api API + * See @ref iface_wl_region. + */ +/** + * @defgroup iface_wl_region The wl_region interface + * + * A region object describes an area. + * + * Region objects are used to describe the opaque and input + * regions of a surface. + */ +extern const struct wl_interface wl_region_interface; +/** + * @page page_iface_wl_subcompositor wl_subcompositor + * @section page_iface_wl_subcompositor_desc Description + * + * The global interface exposing sub-surface compositing capabilities. + * A wl_surface, that has sub-surfaces associated, is called the + * parent surface. Sub-surfaces can be arbitrarily nested and create + * a tree of sub-surfaces. + * + * The root surface in a tree of sub-surfaces is the main + * surface. The main surface cannot be a sub-surface, because + * sub-surfaces must always have a parent. + * + * A main surface with its sub-surfaces forms a (compound) window. + * For window management purposes, this set of wl_surface objects is + * to be considered as a single window, and it should also behave as + * such. + * + * The aim of sub-surfaces is to offload some of the compositing work + * within a window from clients to the compositor. A prime example is + * a video player with decorations and video in separate wl_surface + * objects. This should allow the compositor to pass YUV video buffer + * processing to dedicated overlay hardware when possible. + * @section page_iface_wl_subcompositor_api API + * See @ref iface_wl_subcompositor. + */ +/** + * @defgroup iface_wl_subcompositor The wl_subcompositor interface + * + * The global interface exposing sub-surface compositing capabilities. + * A wl_surface, that has sub-surfaces associated, is called the + * parent surface. Sub-surfaces can be arbitrarily nested and create + * a tree of sub-surfaces. + * + * The root surface in a tree of sub-surfaces is the main + * surface. The main surface cannot be a sub-surface, because + * sub-surfaces must always have a parent. + * + * A main surface with its sub-surfaces forms a (compound) window. + * For window management purposes, this set of wl_surface objects is + * to be considered as a single window, and it should also behave as + * such. + * + * The aim of sub-surfaces is to offload some of the compositing work + * within a window from clients to the compositor. A prime example is + * a video player with decorations and video in separate wl_surface + * objects. This should allow the compositor to pass YUV video buffer + * processing to dedicated overlay hardware when possible. + */ +extern const struct wl_interface wl_subcompositor_interface; +/** + * @page page_iface_wl_subsurface wl_subsurface + * @section page_iface_wl_subsurface_desc Description + * + * An additional interface to a wl_surface object, which has been + * made a sub-surface. A sub-surface has one parent surface. A + * sub-surface's size and position are not limited to that of the parent. + * Particularly, a sub-surface is not automatically clipped to its + * parent's area. + * + * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped. The order of which one happens + * first is irrelevant. A sub-surface is hidden if the parent becomes + * hidden, or if a NULL wl_buffer is applied. These rules apply + * recursively through the tree of surfaces. + * + * The behaviour of a wl_surface.commit request on a sub-surface + * depends on the sub-surface's mode. The possible modes are + * synchronized and desynchronized, see methods + * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + * mode caches the wl_surface state to be applied when the parent's + * state gets applied, and desynchronized mode applies the pending + * wl_surface state directly. A sub-surface is initially in the + * synchronized mode. + * + * Sub-surfaces have also other kind of state, which is managed by + * wl_subsurface requests, as opposed to wl_surface requests. This + * state includes the sub-surface position relative to the parent + * surface (wl_subsurface.set_position), and the stacking order of + * the parent and its sub-surfaces (wl_subsurface.place_above and + * .place_below). This state is applied when the parent surface's + * wl_surface state is applied, regardless of the sub-surface's mode. + * As the exception, set_sync and set_desync are effective immediately. + * + * The main surface can be thought to be always in desynchronized mode, + * since it does not have a parent in the sub-surfaces sense. + * + * Even if a sub-surface is in desynchronized mode, it will behave as + * in synchronized mode, if its parent surface behaves as in + * synchronized mode. This rule is applied recursively throughout the + * tree of surfaces. This means, that one can set a sub-surface into + * synchronized mode, and then assume that all its child and grand-child + * sub-surfaces are synchronized, too, without explicitly setting them. + * + * If the wl_surface associated with the wl_subsurface is destroyed, the + * wl_subsurface object becomes inert. Note, that destroying either object + * takes effect immediately. If you need to synchronize the removal + * of a sub-surface to the parent surface update, unmap the sub-surface + * first by attaching a NULL wl_buffer, update parent, and then destroy + * the sub-surface. + * + * If the parent wl_surface object is destroyed, the sub-surface is + * unmapped. + * @section page_iface_wl_subsurface_api API + * See @ref iface_wl_subsurface. + */ +/** + * @defgroup iface_wl_subsurface The wl_subsurface interface + * + * An additional interface to a wl_surface object, which has been + * made a sub-surface. A sub-surface has one parent surface. A + * sub-surface's size and position are not limited to that of the parent. + * Particularly, a sub-surface is not automatically clipped to its + * parent's area. + * + * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped. The order of which one happens + * first is irrelevant. A sub-surface is hidden if the parent becomes + * hidden, or if a NULL wl_buffer is applied. These rules apply + * recursively through the tree of surfaces. + * + * The behaviour of a wl_surface.commit request on a sub-surface + * depends on the sub-surface's mode. The possible modes are + * synchronized and desynchronized, see methods + * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + * mode caches the wl_surface state to be applied when the parent's + * state gets applied, and desynchronized mode applies the pending + * wl_surface state directly. A sub-surface is initially in the + * synchronized mode. + * + * Sub-surfaces have also other kind of state, which is managed by + * wl_subsurface requests, as opposed to wl_surface requests. This + * state includes the sub-surface position relative to the parent + * surface (wl_subsurface.set_position), and the stacking order of + * the parent and its sub-surfaces (wl_subsurface.place_above and + * .place_below). This state is applied when the parent surface's + * wl_surface state is applied, regardless of the sub-surface's mode. + * As the exception, set_sync and set_desync are effective immediately. + * + * The main surface can be thought to be always in desynchronized mode, + * since it does not have a parent in the sub-surfaces sense. + * + * Even if a sub-surface is in desynchronized mode, it will behave as + * in synchronized mode, if its parent surface behaves as in + * synchronized mode. This rule is applied recursively throughout the + * tree of surfaces. This means, that one can set a sub-surface into + * synchronized mode, and then assume that all its child and grand-child + * sub-surfaces are synchronized, too, without explicitly setting them. + * + * If the wl_surface associated with the wl_subsurface is destroyed, the + * wl_subsurface object becomes inert. Note, that destroying either object + * takes effect immediately. If you need to synchronize the removal + * of a sub-surface to the parent surface update, unmap the sub-surface + * first by attaching a NULL wl_buffer, update parent, and then destroy + * the sub-surface. + * + * If the parent wl_surface object is destroyed, the sub-surface is + * unmapped. + */ +extern const struct wl_interface wl_subsurface_interface; + +#ifndef WL_DISPLAY_ERROR_ENUM +#define WL_DISPLAY_ERROR_ENUM +/** + * @ingroup iface_wl_display + * global error values + * + * These errors are global and can be emitted in response to any + * server request. + */ +enum wl_display_error { + /** + * server couldn't find object + */ + WL_DISPLAY_ERROR_INVALID_OBJECT = 0, + /** + * method doesn't exist on the specified interface + */ + WL_DISPLAY_ERROR_INVALID_METHOD = 1, + /** + * server is out of memory + */ + WL_DISPLAY_ERROR_NO_MEMORY = 2, +}; +#endif /* WL_DISPLAY_ERROR_ENUM */ + +/** + * @ingroup iface_wl_display + * @struct wl_display_listener + */ +struct wl_display_listener { + /** + * fatal error event + * + * The error event is sent out when a fatal (non-recoverable) + * error has occurred. The object_id argument is the object where + * the error occurred, most often in response to a request to that + * object. The code identifies the error and is defined by the + * object interface. As such, each interface defines its own set of + * error codes. The message is a brief description of the error, + * for (debugging) convenience. + * @param object_id object where the error occurred + * @param code error code + * @param message error description + */ + void (*error)(void *data, + struct wl_display *wl_display, + void *object_id, + uint32_t code, + const char *message); + /** + * acknowledge object ID deletion + * + * This event is used internally by the object ID management + * logic. When a client deletes an object, the server will send + * this event to acknowledge that it has seen the delete request. + * When the client receives this event, it will know that it can + * safely reuse the object ID. + * @param id deleted object ID + */ + void (*delete_id)(void *data, + struct wl_display *wl_display, + uint32_t id); +}; + +/** + * @ingroup iface_wl_display + */ +static inline int +wl_display_add_listener(struct wl_display *wl_display, + const struct wl_display_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_display, + (void (**)(void)) listener, data); +} + +#define WL_DISPLAY_SYNC 0 +#define WL_DISPLAY_GET_REGISTRY 1 + +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_ERROR_SINCE_VERSION 1 +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_SYNC_SINCE_VERSION 1 +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 + +/** @ingroup iface_wl_display */ +static inline void +wl_display_set_user_data(struct wl_display *wl_display, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data); +} + +/** @ingroup iface_wl_display */ +static inline void * +wl_display_get_user_data(struct wl_display *wl_display) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_display); +} + +static inline uint32_t +wl_display_get_version(struct wl_display *wl_display) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_display); +} + +/** + * @ingroup iface_wl_display + * + * The sync request asks the server to emit the 'done' event + * on the returned wl_callback object. Since requests are + * handled in-order and events are delivered in-order, this can + * be used as a barrier to ensure all previous requests and the + * resulting events have been handled. + * + * The object returned by this request will be destroyed by the + * compositor after the callback is fired and as such the client must not + * attempt to use it after that point. + * + * The callback_data passed in the callback is the event serial. + */ +static inline struct wl_callback * +wl_display_sync(struct wl_display *wl_display) +{ + struct wl_proxy *callback; + + callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display, + WL_DISPLAY_SYNC, &wl_callback_interface, NULL); + + return (struct wl_callback *) callback; +} + +/** + * @ingroup iface_wl_display + * + * This request creates a registry object that allows the client + * to list and bind the global objects available from the + * compositor. + */ +static inline struct wl_registry * +wl_display_get_registry(struct wl_display *wl_display) +{ + struct wl_proxy *registry; + + registry = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display, + WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL); + + return (struct wl_registry *) registry; +} + +/** + * @ingroup iface_wl_registry + * @struct wl_registry_listener + */ +struct wl_registry_listener { + /** + * announce global object + * + * Notify the client of global objects. + * + * The event notifies the client that a global object with the + * given name is now available, and it implements the given version + * of the given interface. + * @param name numeric name of the global object + * @param interface interface implemented by the object + * @param version interface version + */ + void (*global)(void *data, + struct wl_registry *wl_registry, + uint32_t name, + const char *interface, + uint32_t version); + /** + * announce removal of global object + * + * Notify the client of removed global objects. + * + * This event notifies the client that the global identified by + * name is no longer available. If the client bound to the global + * using the bind request, the client should now destroy that + * object. + * + * The object remains valid and requests to the object will be + * ignored until the client destroys it, to avoid races between the + * global going away and a client sending a request to it. + * @param name numeric name of the global object + */ + void (*global_remove)(void *data, + struct wl_registry *wl_registry, + uint32_t name); +}; + +/** + * @ingroup iface_wl_registry + */ +static inline int +wl_registry_add_listener(struct wl_registry *wl_registry, + const struct wl_registry_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_registry, + (void (**)(void)) listener, data); +} + +#define WL_REGISTRY_BIND 0 + +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_BIND_SINCE_VERSION 1 + +/** @ingroup iface_wl_registry */ +static inline void +wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data); +} + +/** @ingroup iface_wl_registry */ +static inline void * +wl_registry_get_user_data(struct wl_registry *wl_registry) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_registry); +} + +static inline uint32_t +wl_registry_get_version(struct wl_registry *wl_registry) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_registry); +} + +/** @ingroup iface_wl_registry */ +static inline void +wl_registry_destroy(struct wl_registry *wl_registry) +{ + wl_proxy_destroy((struct wl_proxy *) wl_registry); +} + +/** + * @ingroup iface_wl_registry + * + * Binds a new, client-created object to the server using the + * specified name as the identifier. + */ +static inline void * +wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) wl_registry, + WL_REGISTRY_BIND, interface, version, name, interface->name, version, NULL); + + return (void *) id; +} + +/** + * @ingroup iface_wl_callback + * @struct wl_callback_listener + */ +struct wl_callback_listener { + /** + * done event + * + * Notify the client when the related request is done. + * @param callback_data request-specific data for the callback + */ + void (*done)(void *data, + struct wl_callback *wl_callback, + uint32_t callback_data); +}; + +/** + * @ingroup iface_wl_callback + */ +static inline int +wl_callback_add_listener(struct wl_callback *wl_callback, + const struct wl_callback_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_callback, + (void (**)(void)) listener, data); +} + +/** + * @ingroup iface_wl_callback + */ +#define WL_CALLBACK_DONE_SINCE_VERSION 1 + + +/** @ingroup iface_wl_callback */ +static inline void +wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data); +} + +/** @ingroup iface_wl_callback */ +static inline void * +wl_callback_get_user_data(struct wl_callback *wl_callback) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_callback); +} + +static inline uint32_t +wl_callback_get_version(struct wl_callback *wl_callback) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_callback); +} + +/** @ingroup iface_wl_callback */ +static inline void +wl_callback_destroy(struct wl_callback *wl_callback) +{ + wl_proxy_destroy((struct wl_proxy *) wl_callback); +} + +#define WL_COMPOSITOR_CREATE_SURFACE 0 +#define WL_COMPOSITOR_CREATE_REGION 1 + + +/** + * @ingroup iface_wl_compositor + */ +#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_compositor + */ +#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 + +/** @ingroup iface_wl_compositor */ +static inline void +wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data); +} + +/** @ingroup iface_wl_compositor */ +static inline void * +wl_compositor_get_user_data(struct wl_compositor *wl_compositor) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor); +} + +static inline uint32_t +wl_compositor_get_version(struct wl_compositor *wl_compositor) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_compositor); +} + +/** @ingroup iface_wl_compositor */ +static inline void +wl_compositor_destroy(struct wl_compositor *wl_compositor) +{ + wl_proxy_destroy((struct wl_proxy *) wl_compositor); +} + +/** + * @ingroup iface_wl_compositor + * + * Ask the compositor to create a new surface. + */ +static inline struct wl_surface * +wl_compositor_create_surface(struct wl_compositor *wl_compositor) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL); + + return (struct wl_surface *) id; +} + +/** + * @ingroup iface_wl_compositor + * + * Ask the compositor to create a new region. + */ +static inline struct wl_region * +wl_compositor_create_region(struct wl_compositor *wl_compositor) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, NULL); + + return (struct wl_region *) id; +} + +#define WL_SHM_POOL_CREATE_BUFFER 0 +#define WL_SHM_POOL_DESTROY 1 +#define WL_SHM_POOL_RESIZE 2 + + +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 + +/** @ingroup iface_wl_shm_pool */ +static inline void +wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data); +} + +/** @ingroup iface_wl_shm_pool */ +static inline void * +wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool); +} + +static inline uint32_t +wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool); +} + +/** + * @ingroup iface_wl_shm_pool + * + * Create a wl_buffer object from the pool. + * + * The buffer is created offset bytes into the pool and has + * width and height as specified. The stride argument specifies + * the number of bytes from the beginning of one row to the beginning + * of the next. The format is the pixel format of the buffer and + * must be one of those advertised through the wl_shm.format event. + * + * A buffer will keep a reference to the pool it was created from + * so it is valid to destroy the pool immediately after creating + * a buffer from it. + */ +static inline struct wl_buffer * +wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, NULL, offset, width, height, stride, format); + + return (struct wl_buffer *) id; +} + +/** + * @ingroup iface_wl_shm_pool + * + * Destroy the shared memory pool. + * + * The mmapped memory will be released when all + * buffers that have been created from this pool + * are gone. + */ +static inline void +wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_shm_pool); +} + +/** + * @ingroup iface_wl_shm_pool + * + * This request will cause the server to remap the backing memory + * for the pool from the file descriptor passed when the pool was + * created, but using the new size. This request can only be + * used to make the pool bigger. + */ +static inline void +wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_RESIZE, size); +} + +#ifndef WL_SHM_ERROR_ENUM +#define WL_SHM_ERROR_ENUM +/** + * @ingroup iface_wl_shm + * wl_shm error values + * + * These errors can be emitted in response to wl_shm requests. + */ +enum wl_shm_error { + /** + * buffer format is not known + */ + WL_SHM_ERROR_INVALID_FORMAT = 0, + /** + * invalid size or stride during pool or buffer creation + */ + WL_SHM_ERROR_INVALID_STRIDE = 1, + /** + * mmapping the file descriptor failed + */ + WL_SHM_ERROR_INVALID_FD = 2, +}; +#endif /* WL_SHM_ERROR_ENUM */ + +#ifndef WL_SHM_FORMAT_ENUM +#define WL_SHM_FORMAT_ENUM +/** + * @ingroup iface_wl_shm + * pixel formats + * + * This describes the memory layout of an individual pixel. + * + * All renderers should support argb8888 and xrgb8888 but any other + * formats are optional and may not be supported by the particular + * renderer in use. + * + * The drm format codes match the macros defined in drm_fourcc.h. + * The formats actually supported by the compositor will be + * reported by the format event. + */ +enum wl_shm_format { + /** + * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ARGB8888 = 0, + /** + * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XRGB8888 = 1, + /** + * 8-bit color index format, [7:0] C + */ + WL_SHM_FORMAT_C8 = 0x20203843, + /** + * 8-bit RGB format, [7:0] R:G:B 3:3:2 + */ + WL_SHM_FORMAT_RGB332 = 0x38424752, + /** + * 8-bit BGR format, [7:0] B:G:R 2:3:3 + */ + WL_SHM_FORMAT_BGR233 = 0x38524742, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XRGB4444 = 0x32315258, + /** + * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XBGR4444 = 0x32314258, + /** + * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBX4444 = 0x32315852, + /** + * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRX4444 = 0x32315842, + /** + * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ARGB4444 = 0x32315241, + /** + * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ABGR4444 = 0x32314241, + /** + * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBA4444 = 0x32314152, + /** + * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRA4444 = 0x32314142, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XRGB1555 = 0x35315258, + /** + * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XBGR1555 = 0x35314258, + /** + * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBX5551 = 0x35315852, + /** + * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRX5551 = 0x35315842, + /** + * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ARGB1555 = 0x35315241, + /** + * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ABGR1555 = 0x35314241, + /** + * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBA5551 = 0x35314152, + /** + * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRA5551 = 0x35314142, + /** + * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian + */ + WL_SHM_FORMAT_RGB565 = 0x36314752, + /** + * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian + */ + WL_SHM_FORMAT_BGR565 = 0x36314742, + /** + * 24-bit RGB format, [23:0] R:G:B little endian + */ + WL_SHM_FORMAT_RGB888 = 0x34324752, + /** + * 24-bit BGR format, [23:0] B:G:R little endian + */ + WL_SHM_FORMAT_BGR888 = 0x34324742, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XBGR8888 = 0x34324258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBX8888 = 0x34325852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRX8888 = 0x34325842, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ABGR8888 = 0x34324241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBA8888 = 0x34324152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRA8888 = 0x34324142, + /** + * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XRGB2101010 = 0x30335258, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XBGR2101010 = 0x30334258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBX1010102 = 0x30335852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRX1010102 = 0x30335842, + /** + * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ARGB2101010 = 0x30335241, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ABGR2101010 = 0x30334241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBA1010102 = 0x30334152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRA1010102 = 0x30334142, + /** + * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YUYV = 0x56595559, + /** + * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YVYU = 0x55595659, + /** + * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_UYVY = 0x59565955, + /** + * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_VYUY = 0x59555956, + /** + * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian + */ + WL_SHM_FORMAT_AYUV = 0x56555941, + /** + * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV12 = 0x3231564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV21 = 0x3132564e, + /** + * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV16 = 0x3631564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV61 = 0x3136564e, + /** + * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV410 = 0x39565559, + /** + * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU410 = 0x39555659, + /** + * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV411 = 0x31315559, + /** + * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU411 = 0x31315659, + /** + * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV420 = 0x32315559, + /** + * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU420 = 0x32315659, + /** + * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV422 = 0x36315559, + /** + * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU422 = 0x36315659, + /** + * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV444 = 0x34325559, + /** + * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU444 = 0x34325659, +}; +#endif /* WL_SHM_FORMAT_ENUM */ + +/** + * @ingroup iface_wl_shm + * @struct wl_shm_listener + */ +struct wl_shm_listener { + /** + * pixel format description + * + * Informs the client about a valid pixel format that can be used + * for buffers. Known formats include argb8888 and xrgb8888. + * @param format buffer pixel format + */ + void (*format)(void *data, + struct wl_shm *wl_shm, + uint32_t format); +}; + +/** + * @ingroup iface_wl_shm + */ +static inline int +wl_shm_add_listener(struct wl_shm *wl_shm, + const struct wl_shm_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_shm, + (void (**)(void)) listener, data); +} + +#define WL_SHM_CREATE_POOL 0 + +/** + * @ingroup iface_wl_shm + */ +#define WL_SHM_FORMAT_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shm + */ +#define WL_SHM_CREATE_POOL_SINCE_VERSION 1 + +/** @ingroup iface_wl_shm */ +static inline void +wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data); +} + +/** @ingroup iface_wl_shm */ +static inline void * +wl_shm_get_user_data(struct wl_shm *wl_shm) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shm); +} + +static inline uint32_t +wl_shm_get_version(struct wl_shm *wl_shm) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shm); +} + +/** @ingroup iface_wl_shm */ +static inline void +wl_shm_destroy(struct wl_shm *wl_shm) +{ + wl_proxy_destroy((struct wl_proxy *) wl_shm); +} + +/** + * @ingroup iface_wl_shm + * + * Create a new wl_shm_pool object. + * + * The pool can be used to create shared memory based buffer + * objects. The server will mmap size bytes of the passed file + * descriptor, to use as backing memory for the pool. + */ +static inline struct wl_shm_pool * +wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm, + WL_SHM_CREATE_POOL, &wl_shm_pool_interface, NULL, fd, size); + + return (struct wl_shm_pool *) id; +} + +/** + * @ingroup iface_wl_buffer + * @struct wl_buffer_listener + */ +struct wl_buffer_listener { + /** + * compositor releases buffer + * + * Sent when this wl_buffer is no longer used by the compositor. + * The client is now free to reuse or destroy this buffer and its + * backing storage. + * + * If a client receives a release event before the frame callback + * requested in the same wl_surface.commit that attaches this + * wl_buffer to a surface, then the client is immediately free to + * reuse the buffer and its backing storage, and does not need a + * second buffer for the next surface content update. Typically + * this is possible, when the compositor maintains a copy of the + * wl_surface contents, e.g. as a GL texture. This is an important + * optimization for GL(ES) compositors with wl_shm clients. + */ + void (*release)(void *data, + struct wl_buffer *wl_buffer); +}; + +/** + * @ingroup iface_wl_buffer + */ +static inline int +wl_buffer_add_listener(struct wl_buffer *wl_buffer, + const struct wl_buffer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_buffer, + (void (**)(void)) listener, data); +} + +#define WL_BUFFER_DESTROY 0 + +/** + * @ingroup iface_wl_buffer + */ +#define WL_BUFFER_RELEASE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_buffer + */ +#define WL_BUFFER_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wl_buffer */ +static inline void +wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data); +} + +/** @ingroup iface_wl_buffer */ +static inline void * +wl_buffer_get_user_data(struct wl_buffer *wl_buffer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer); +} + +static inline uint32_t +wl_buffer_get_version(struct wl_buffer *wl_buffer) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_buffer); +} + +/** + * @ingroup iface_wl_buffer + * + * Destroy a buffer. If and how you need to release the backing + * storage is defined by the buffer factory interface. + * + * For possible side-effects to a surface, see wl_surface.attach. + */ +static inline void +wl_buffer_destroy(struct wl_buffer *wl_buffer) +{ + wl_proxy_marshal((struct wl_proxy *) wl_buffer, + WL_BUFFER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_buffer); +} + +#ifndef WL_DATA_OFFER_ERROR_ENUM +#define WL_DATA_OFFER_ERROR_ENUM +enum wl_data_offer_error { + /** + * finish request was called untimely + */ + WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, + /** + * action mask contains invalid values + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, + /** + * action argument has an invalid value + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, + /** + * offer doesn't accept this request + */ + WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, +}; +#endif /* WL_DATA_OFFER_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_offer + * @struct wl_data_offer_listener + */ +struct wl_data_offer_listener { + /** + * advertise offered mime type + * + * Sent immediately after creating the wl_data_offer object. One + * event per offered mime type. + * @param mime_type offered mime type + */ + void (*offer)(void *data, + struct wl_data_offer *wl_data_offer, + const char *mime_type); + /** + * notify the source-side available actions + * + * This event indicates the actions offered by the data source. + * It will be sent right after wl_data_device.enter, or anytime the + * source side changes its offered actions through + * wl_data_source.set_actions. + * @param source_actions actions offered by the data source + * @since 3 + */ + void (*source_actions)(void *data, + struct wl_data_offer *wl_data_offer, + uint32_t source_actions); + /** + * notify the selected action + * + * This event indicates the action selected by the compositor + * after matching the source/destination side actions. Only one + * action (or none) will be offered here. + * + * This event can be emitted multiple times during the + * drag-and-drop operation in response to destination side action + * changes through wl_data_offer.set_actions. + * + * This event will no longer be emitted after wl_data_device.drop + * happened on the drag-and-drop destination, the client must honor + * the last action received, or the last preferred one set through + * wl_data_offer.set_actions when handling an "ask" action. + * + * Compositors may also change the selected action on the fly, + * mainly in response to keyboard modifier changes during the + * drag-and-drop operation. + * + * The most recent action received is always the valid one. Prior + * to receiving wl_data_device.drop, the chosen action may change + * (e.g. due to keyboard modifiers being pressed). At the time of + * receiving wl_data_device.drop the drag-and-drop destination must + * honor the last action received. + * + * Action changes may still happen after wl_data_device.drop, + * especially on "ask" actions, where the drag-and-drop destination + * may choose another action afterwards. Action changes happening + * at this stage are always the result of inter-client negotiation, + * the compositor shall no longer be able to induce a different + * action. + * + * Upon "ask" actions, it is expected that the drag-and-drop + * destination may potentially choose a different action and/or + * mime type, based on wl_data_offer.source_actions and finally + * chosen by the user (e.g. popping up a menu with the available + * options). The final wl_data_offer.set_actions and + * wl_data_offer.accept requests must happen before the call to + * wl_data_offer.finish. + * @param dnd_action action selected by the compositor + * @since 3 + */ + void (*action)(void *data, + struct wl_data_offer *wl_data_offer, + uint32_t dnd_action); +}; + +/** + * @ingroup iface_wl_data_offer + */ +static inline int +wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer, + const struct wl_data_offer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer, + (void (**)(void)) listener, data); +} + +#define WL_DATA_OFFER_ACCEPT 0 +#define WL_DATA_OFFER_RECEIVE 1 +#define WL_DATA_OFFER_DESTROY 2 +#define WL_DATA_OFFER_FINISH 3 +#define WL_DATA_OFFER_SET_ACTIONS 4 + +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 + +/** @ingroup iface_wl_data_offer */ +static inline void +wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data); +} + +/** @ingroup iface_wl_data_offer */ +static inline void * +wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer); +} + +static inline uint32_t +wl_data_offer_get_version(struct wl_data_offer *wl_data_offer) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_offer); +} + +/** + * @ingroup iface_wl_data_offer + * + * Indicate that the client can accept the given mime type, or + * NULL for not accepted. + * + * For objects of version 2 or older, this request is used by the + * client to give feedback whether the client can receive the given + * mime type, or NULL if none is accepted; the feedback does not + * determine whether the drag-and-drop operation succeeds or not. + * + * For objects of version 3 or newer, this request determines the + * final result of the drag-and-drop operation. If the end result + * is that no mime types were accepted, the drag-and-drop operation + * will be cancelled and the corresponding drag source will receive + * wl_data_source.cancelled. Clients may still use this event in + * conjunction with wl_data_source.action for feedback. + */ +static inline void +wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_ACCEPT, serial, mime_type); +} + +/** + * @ingroup iface_wl_data_offer + * + * To transfer the offered data, the client issues this request + * and indicates the mime type it wants to receive. The transfer + * happens through the passed file descriptor (typically created + * with the pipe system call). The source client writes the data + * in the mime type representation requested and then closes the + * file descriptor. + * + * The receiving client reads from the read end of the pipe until + * EOF and then closes its end, at which point the transfer is + * complete. + * + * This request may happen multiple times for different mime types, + * both before and after wl_data_device.drop. Drag-and-drop destination + * clients may preemptively fetch data or examine it more closely to + * determine acceptance. + */ +static inline void +wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_RECEIVE, mime_type, fd); +} + +/** + * @ingroup iface_wl_data_offer + * + * Destroy the data offer. + */ +static inline void +wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_data_offer); +} + +/** + * @ingroup iface_wl_data_offer + * + * Notifies the compositor that the drag destination successfully + * finished the drag-and-drop operation. + * + * Upon receiving this request, the compositor will emit + * wl_data_source.dnd_finished on the drag source client. + * + * It is a client error to perform other requests than + * wl_data_offer.destroy after this one. It is also an error to perform + * this request after a NULL mime type has been set in + * wl_data_offer.accept or no action was received through + * wl_data_offer.action. + */ +static inline void +wl_data_offer_finish(struct wl_data_offer *wl_data_offer) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_FINISH); +} + +/** + * @ingroup iface_wl_data_offer + * + * Sets the actions that the destination side client supports for + * this operation. This request may trigger the emission of + * wl_data_source.action and wl_data_offer.action events if the compositor + * needs to change the selected action. + * + * This request can be called multiple times throughout the + * drag-and-drop operation, typically in response to wl_data_device.enter + * or wl_data_device.motion events. + * + * This request determines the final result of the drag-and-drop + * operation. If the end result is that no action is accepted, + * the drag source will receive wl_drag_source.cancelled. + * + * The dnd_actions argument must contain only values expressed in the + * wl_data_device_manager.dnd_actions enum, and the preferred_action + * argument must only contain one of those values set, otherwise it + * will result in a protocol error. + * + * While managing an "ask" action, the destination drag-and-drop client + * may perform further wl_data_offer.receive requests, and is expected + * to perform one last wl_data_offer.set_actions request with a preferred + * action other than "ask" (and optionally wl_data_offer.accept) before + * requesting wl_data_offer.finish, in order to convey the action selected + * by the user. If the preferred action is not in the + * wl_data_offer.source_actions mask, an error will be raised. + * + * If the "ask" action is dismissed (e.g. user cancellation), the client + * is expected to perform wl_data_offer.destroy right away. + * + * This request can only be made on drag-and-drop offers, a protocol error + * will be raised otherwise. + */ +static inline void +wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_SET_ACTIONS, dnd_actions, preferred_action); +} + +#ifndef WL_DATA_SOURCE_ERROR_ENUM +#define WL_DATA_SOURCE_ERROR_ENUM +enum wl_data_source_error { + /** + * action mask contains invalid values + */ + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, + /** + * source doesn't accept this request + */ + WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, +}; +#endif /* WL_DATA_SOURCE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_source + * @struct wl_data_source_listener + */ +struct wl_data_source_listener { + /** + * a target accepts an offered mime type + * + * Sent when a target accepts pointer_focus or motion events. If + * a target does not accept any of the offered types, type is NULL. + * + * Used for feedback during drag-and-drop. + * @param mime_type mime type accepted by the target + */ + void (*target)(void *data, + struct wl_data_source *wl_data_source, + const char *mime_type); + /** + * send the data + * + * Request for data from the client. Send the data as the + * specified mime type over the passed file descriptor, then close + * it. + * @param mime_type mime type for the data + * @param fd file descriptor for the data + */ + void (*send)(void *data, + struct wl_data_source *wl_data_source, + const char *mime_type, + int32_t fd); + /** + * selection was cancelled + * + * This data source is no longer valid. There are several reasons + * why this could happen: + * + * - The data source has been replaced by another data source. - + * The drag-and-drop operation was performed, but the drop + * destination did not accept any of the mime types offered through + * wl_data_source.target. - The drag-and-drop operation was + * performed, but the drop destination did not select any of the + * actions present in the mask offered through + * wl_data_source.action. - The drag-and-drop operation was + * performed but didn't happen over a surface. - The compositor + * cancelled the drag-and-drop operation (e.g. compositor dependent + * timeouts to avoid stale drag-and-drop transfers). + * + * The client should clean up and destroy this data source. + * + * For objects of version 2 or older, wl_data_source.cancelled will + * only be emitted if the data source was replaced by another data + * source. + */ + void (*cancelled)(void *data, + struct wl_data_source *wl_data_source); + /** + * the drag-and-drop operation physically finished + * + * The user performed the drop action. This event does not + * indicate acceptance, wl_data_source.cancelled may still be + * emitted afterwards if the drop destination does not accept any + * mime type. + * + * However, this event might however not be received if the + * compositor cancelled the drag-and-drop operation before this + * event could happen. + * + * Note that the data_source may still be used in the future and + * should not be destroyed here. + * @since 3 + */ + void (*dnd_drop_performed)(void *data, + struct wl_data_source *wl_data_source); + /** + * the drag-and-drop operation concluded + * + * The drop destination finished interoperating with this data + * source, so the client is now free to destroy this data source + * and free all associated data. + * + * If the action used to perform the operation was "move", the + * source can now delete the transferred data. + * @since 3 + */ + void (*dnd_finished)(void *data, + struct wl_data_source *wl_data_source); + /** + * notify the selected action + * + * This event indicates the action selected by the compositor + * after matching the source/destination side actions. Only one + * action (or none) will be offered here. + * + * This event can be emitted multiple times during the + * drag-and-drop operation, mainly in response to destination side + * changes through wl_data_offer.set_actions, and as the data + * device enters/leaves surfaces. + * + * It is only possible to receive this event after + * wl_data_source.dnd_drop_performed if the drag-and-drop operation + * ended in an "ask" action, in which case the final + * wl_data_source.action event will happen immediately before + * wl_data_source.dnd_finished. + * + * Compositors may also change the selected action on the fly, + * mainly in response to keyboard modifier changes during the + * drag-and-drop operation. + * + * The most recent action received is always the valid one. The + * chosen action may change alongside negotiation (e.g. an "ask" + * action can turn into a "move" operation), so the effects of the + * final action must always be applied in + * wl_data_offer.dnd_finished. + * + * Clients can trigger cursor surface changes from this point, so + * they reflect the current action. + * @param dnd_action action selected by the compositor + * @since 3 + */ + void (*action)(void *data, + struct wl_data_source *wl_data_source, + uint32_t dnd_action); +}; + +/** + * @ingroup iface_wl_data_source + */ +static inline int +wl_data_source_add_listener(struct wl_data_source *wl_data_source, + const struct wl_data_source_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_data_source, + (void (**)(void)) listener, data); +} + +#define WL_DATA_SOURCE_OFFER 0 +#define WL_DATA_SOURCE_DESTROY 1 +#define WL_DATA_SOURCE_SET_ACTIONS 2 + +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 + +/** @ingroup iface_wl_data_source */ +static inline void +wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data); +} + +/** @ingroup iface_wl_data_source */ +static inline void * +wl_data_source_get_user_data(struct wl_data_source *wl_data_source) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source); +} + +static inline uint32_t +wl_data_source_get_version(struct wl_data_source *wl_data_source) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_source); +} + +/** + * @ingroup iface_wl_data_source + * + * This request adds a mime type to the set of mime types + * advertised to targets. Can be called several times to offer + * multiple types. + */ +static inline void +wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_OFFER, mime_type); +} + +/** + * @ingroup iface_wl_data_source + * + * Destroy the data source. + */ +static inline void +wl_data_source_destroy(struct wl_data_source *wl_data_source) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_data_source); +} + +/** + * @ingroup iface_wl_data_source + * + * Sets the actions that the source side client supports for this + * operation. This request may trigger wl_data_source.action and + * wl_data_offer.action events if the compositor needs to change the + * selected action. + * + * The dnd_actions argument must contain only values expressed in the + * wl_data_device_manager.dnd_actions enum, otherwise it will result + * in a protocol error. + * + * This request must be made once only, and can only be made on sources + * used in drag-and-drop, so it must be performed before + * wl_data_device.start_drag. Attempting to use the source other than + * for drag-and-drop will raise a protocol error. + */ +static inline void +wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_SET_ACTIONS, dnd_actions); +} + +#ifndef WL_DATA_DEVICE_ERROR_ENUM +#define WL_DATA_DEVICE_ERROR_ENUM +enum wl_data_device_error { + /** + * given wl_surface has another role + */ + WL_DATA_DEVICE_ERROR_ROLE = 0, +}; +#endif /* WL_DATA_DEVICE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_device + * @struct wl_data_device_listener + */ +struct wl_data_device_listener { + /** + * introduce a new wl_data_offer + * + * The data_offer event introduces a new wl_data_offer object, + * which will subsequently be used in either the data_device.enter + * event (for drag-and-drop) or the data_device.selection event + * (for selections). Immediately following the + * data_device_data_offer event, the new data_offer object will + * send out data_offer.offer events to describe the mime types it + * offers. + * @param id the new data_offer object + */ + void (*data_offer)(void *data, + struct wl_data_device *wl_data_device, + struct wl_data_offer *id); + /** + * initiate drag-and-drop session + * + * This event is sent when an active drag-and-drop pointer enters + * a surface owned by the client. The position of the pointer at + * enter time is provided by the x and y arguments, in + * surface-local coordinates. + * @param serial serial number of the enter event + * @param surface client surface entered + * @param x surface-local x coordinate + * @param y surface-local y coordinate + * @param id source data_offer object + */ + void (*enter)(void *data, + struct wl_data_device *wl_data_device, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer *id); + /** + * end drag-and-drop session + * + * This event is sent when the drag-and-drop pointer leaves the + * surface and the session ends. The client must destroy the + * wl_data_offer introduced at enter time at this point. + */ + void (*leave)(void *data, + struct wl_data_device *wl_data_device); + /** + * drag-and-drop session motion + * + * This event is sent when the drag-and-drop pointer moves within + * the currently focused surface. The new position of the pointer + * is provided by the x and y arguments, in surface-local + * coordinates. + * @param time timestamp with millisecond granularity + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*motion)(void *data, + struct wl_data_device *wl_data_device, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y); + /** + * end drag-and-drop session successfully + * + * The event is sent when a drag-and-drop operation is ended + * because the implicit grab is removed. + * + * The drag-and-drop destination is expected to honor the last + * action received through wl_data_offer.action, if the resulting + * action is "copy" or "move", the destination can still perform + * wl_data_offer.receive requests, and is expected to end all + * transfers with a wl_data_offer.finish request. + * + * If the resulting action is "ask", the action will not be + * considered final. The drag-and-drop destination is expected to + * perform one last wl_data_offer.set_actions request, or + * wl_data_offer.destroy in order to cancel the operation. + */ + void (*drop)(void *data, + struct wl_data_device *wl_data_device); + /** + * advertise new selection + * + * The selection event is sent out to notify the client of a new + * wl_data_offer for the selection for this device. The + * data_device.data_offer and the data_offer.offer events are sent + * out immediately before this event to introduce the data offer + * object. The selection event is sent to a client immediately + * before receiving keyboard focus and when a new selection is set + * while the client has keyboard focus. The data_offer is valid + * until a new data_offer or NULL is received or until the client + * loses keyboard focus. The client must destroy the previous + * selection data_offer, if any, upon receiving this event. + * @param id selection data_offer object + */ + void (*selection)(void *data, + struct wl_data_device *wl_data_device, + struct wl_data_offer *id); +}; + +/** + * @ingroup iface_wl_data_device + */ +static inline int +wl_data_device_add_listener(struct wl_data_device *wl_data_device, + const struct wl_data_device_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_data_device, + (void (**)(void)) listener, data); +} + +#define WL_DATA_DEVICE_START_DRAG 0 +#define WL_DATA_DEVICE_SET_SELECTION 1 +#define WL_DATA_DEVICE_RELEASE 2 + +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 + +/** @ingroup iface_wl_data_device */ +static inline void +wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data); +} + +/** @ingroup iface_wl_data_device */ +static inline void * +wl_data_device_get_user_data(struct wl_data_device *wl_data_device) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device); +} + +static inline uint32_t +wl_data_device_get_version(struct wl_data_device *wl_data_device) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_device); +} + +/** @ingroup iface_wl_data_device */ +static inline void +wl_data_device_destroy(struct wl_data_device *wl_data_device) +{ + wl_proxy_destroy((struct wl_proxy *) wl_data_device); +} + +/** + * @ingroup iface_wl_data_device + * + * This request asks the compositor to start a drag-and-drop + * operation on behalf of the client. + * + * The source argument is the data source that provides the data + * for the eventual data transfer. If source is NULL, enter, leave + * and motion events are sent only to the client that initiated the + * drag and the client is expected to handle the data passing + * internally. + * + * The origin surface is the surface where the drag originates and + * the client must have an active implicit grab that matches the + * serial. + * + * The icon surface is an optional (can be NULL) surface that + * provides an icon to be moved around with the cursor. Initially, + * the top-left corner of the icon surface is placed at the cursor + * hotspot, but subsequent wl_surface.attach request can move the + * relative position. Attach requests must be confirmed with + * wl_surface.commit as usual. The icon surface is given the role of + * a drag-and-drop icon. If the icon surface already has another role, + * it raises a protocol error. + * + * The current and pending input regions of the icon wl_surface are + * cleared, and wl_surface.set_input_region is ignored until the + * wl_surface is no longer used as the icon surface. When the use + * as an icon ends, the current and pending input regions become + * undefined, and the wl_surface is unmapped. + */ +static inline void +wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_START_DRAG, source, origin, icon, serial); +} + +/** + * @ingroup iface_wl_data_device + * + * This request asks the compositor to set the selection + * to the data from the source on behalf of the client. + * + * To unset the selection, set the source to NULL. + */ +static inline void +wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_SET_SELECTION, source, serial); +} + +/** + * @ingroup iface_wl_data_device + * + * This request destroys the data device. + */ +static inline void +wl_data_device_release(struct wl_data_device *wl_data_device) +{ + wl_proxy_marshal((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_RELEASE); + + wl_proxy_destroy((struct wl_proxy *) wl_data_device); +} + +#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +/** + * @ingroup iface_wl_data_device_manager + * drag and drop actions + * + * This is a bitmask of the available/preferred actions in a + * drag-and-drop operation. + * + * In the compositor, the selected action is a result of matching the + * actions offered by the source and destination sides. "action" events + * with a "none" action will be sent to both source and destination if + * there is no match. All further checks will effectively happen on + * (source actions ∩ destination actions). + * + * In addition, compositors may also pick different actions in + * reaction to key modifiers being pressed. One common design that + * is used in major toolkits (and the behavior recommended for + * compositors) is: + * + * - If no modifiers are pressed, the first match (in bit order) + * will be used. + * - Pressing Shift selects "move", if enabled in the mask. + * - Pressing Control selects "copy", if enabled in the mask. + * + * Behavior beyond that is considered implementation-dependent. + * Compositors may for example bind other modifiers (like Alt/Meta) + * or drags initiated with other buttons than BTN_LEFT to specific + * actions (e.g. "ask"). + */ +enum wl_data_device_manager_dnd_action { + /** + * no action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, + /** + * copy action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, + /** + * move action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, + /** + * ask action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, +}; +#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ + +#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0 +#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1 + + +/** + * @ingroup iface_wl_data_device_manager + */ +#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device_manager + */ +#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 + +/** @ingroup iface_wl_data_device_manager */ +static inline void +wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data); +} + +/** @ingroup iface_wl_data_device_manager */ +static inline void * +wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager); +} + +static inline uint32_t +wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager); +} + +/** @ingroup iface_wl_data_device_manager */ +static inline void +wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager) +{ + wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager); +} + +/** + * @ingroup iface_wl_data_device_manager + * + * Create a new data source. + */ +static inline struct wl_data_source * +wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, NULL); + + return (struct wl_data_source *) id; +} + +/** + * @ingroup iface_wl_data_device_manager + * + * Create a new data device for a given seat. + */ +static inline struct wl_data_device * +wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, NULL, seat); + + return (struct wl_data_device *) id; +} + +#ifndef WL_SHELL_ERROR_ENUM +#define WL_SHELL_ERROR_ENUM +enum wl_shell_error { + /** + * given wl_surface has another role + */ + WL_SHELL_ERROR_ROLE = 0, +}; +#endif /* WL_SHELL_ERROR_ENUM */ + +#define WL_SHELL_GET_SHELL_SURFACE 0 + + +/** + * @ingroup iface_wl_shell + */ +#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 + +/** @ingroup iface_wl_shell */ +static inline void +wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data); +} + +/** @ingroup iface_wl_shell */ +static inline void * +wl_shell_get_user_data(struct wl_shell *wl_shell) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shell); +} + +static inline uint32_t +wl_shell_get_version(struct wl_shell *wl_shell) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shell); +} + +/** @ingroup iface_wl_shell */ +static inline void +wl_shell_destroy(struct wl_shell *wl_shell) +{ + wl_proxy_destroy((struct wl_proxy *) wl_shell); +} + +/** + * @ingroup iface_wl_shell + * + * Create a shell surface for an existing surface. This gives + * the wl_surface the role of a shell surface. If the wl_surface + * already has another role, it raises a protocol error. + * + * Only one shell surface can be associated with a given surface. + */ +static inline struct wl_shell_surface * +wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shell, + WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, NULL, surface); + + return (struct wl_shell_surface *) id; +} + +#ifndef WL_SHELL_SURFACE_RESIZE_ENUM +#define WL_SHELL_SURFACE_RESIZE_ENUM +/** + * @ingroup iface_wl_shell_surface + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. The server may + * use this information to adapt its behavior, e.g. choose + * an appropriate cursor image. + */ +enum wl_shell_surface_resize { + /** + * no edge + */ + WL_SHELL_SURFACE_RESIZE_NONE = 0, + /** + * top edge + */ + WL_SHELL_SURFACE_RESIZE_TOP = 1, + /** + * bottom edge + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, + /** + * left edge + */ + WL_SHELL_SURFACE_RESIZE_LEFT = 4, + /** + * top and left edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, + /** + * bottom and left edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, + /** + * right edge + */ + WL_SHELL_SURFACE_RESIZE_RIGHT = 8, + /** + * top and right edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, + /** + * bottom and right edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, +}; +#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ + +#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM +#define WL_SHELL_SURFACE_TRANSIENT_ENUM +/** + * @ingroup iface_wl_shell_surface + * details of transient behaviour + * + * These flags specify details of the expected behaviour + * of transient surfaces. Used in the set_transient request. + */ +enum wl_shell_surface_transient { + /** + * do not set keyboard focus + */ + WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, +}; +#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ + +#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +/** + * @ingroup iface_wl_shell_surface + * different method to set the surface fullscreen + * + * Hints to indicate to the compositor how to deal with a conflict + * between the dimensions of the surface and the dimensions of the + * output. The compositor is free to ignore this parameter. + */ +enum wl_shell_surface_fullscreen_method { + /** + * no preference, apply default policy + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, + /** + * scale, preserve the surface's aspect ratio and center on output + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, + /** + * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, + /** + * no upscaling, center on output and add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, +}; +#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ + +/** + * @ingroup iface_wl_shell_surface + * @struct wl_shell_surface_listener + */ +struct wl_shell_surface_listener { + /** + * ping client + * + * Ping a client to check if it is receiving events and sending + * requests. A client is expected to reply with a pong request. + * @param serial serial number of the ping + */ + void (*ping)(void *data, + struct wl_shell_surface *wl_shell_surface, + uint32_t serial); + /** + * suggest resize + * + * The configure event asks the client to resize its surface. + * + * The size is a hint, in the sense that the client is free to + * ignore it if it doesn't resize, pick a smaller size (to satisfy + * aspect ratio or resize in steps of NxM pixels). + * + * The edges parameter provides a hint about how the surface was + * resized. The client may use this information to decide how to + * adjust its content to the new size (e.g. a scrolling area might + * adjust its content position to leave the viewable content + * unmoved). + * + * The client is free to dismiss all but the last configure event + * it received. + * + * The width and height arguments specify the size of the window in + * surface-local coordinates. + * @param edges how the surface was resized + * @param width new width of the surface + * @param height new height of the surface + */ + void (*configure)(void *data, + struct wl_shell_surface *wl_shell_surface, + uint32_t edges, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup grab is broken, + * that is, when the user clicks a surface that doesn't belong to + * the client owning the popup surface. + */ + void (*popup_done)(void *data, + struct wl_shell_surface *wl_shell_surface); +}; + +/** + * @ingroup iface_wl_shell_surface + */ +static inline int +wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, + const struct wl_shell_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface, + (void (**)(void)) listener, data); +} + +#define WL_SHELL_SURFACE_PONG 0 +#define WL_SHELL_SURFACE_MOVE 1 +#define WL_SHELL_SURFACE_RESIZE 2 +#define WL_SHELL_SURFACE_SET_TOPLEVEL 3 +#define WL_SHELL_SURFACE_SET_TRANSIENT 4 +#define WL_SHELL_SURFACE_SET_FULLSCREEN 5 +#define WL_SHELL_SURFACE_SET_POPUP 6 +#define WL_SHELL_SURFACE_SET_MAXIMIZED 7 +#define WL_SHELL_SURFACE_SET_TITLE 8 +#define WL_SHELL_SURFACE_SET_CLASS 9 + +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 + +/** @ingroup iface_wl_shell_surface */ +static inline void +wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data); +} + +/** @ingroup iface_wl_shell_surface */ +static inline void * +wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface); +} + +static inline uint32_t +wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface); +} + +/** @ingroup iface_wl_shell_surface */ +static inline void +wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface) +{ + wl_proxy_destroy((struct wl_proxy *) wl_shell_surface); +} + +/** + * @ingroup iface_wl_shell_surface + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. + */ +static inline void +wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_PONG, serial); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Start a pointer-driven move of the surface. + * + * This request must be used in response to a button press event. + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized). + */ +static inline void +wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_MOVE, seat, serial); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Start a pointer-driven resizing of the surface. + * + * This request must be used in response to a button press event. + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + */ +static inline void +wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_RESIZE, seat, serial, edges); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a toplevel surface. + * + * A toplevel surface is not fullscreen, maximized or transient. + */ +static inline void +wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TOPLEVEL); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface relative to an existing surface. + * + * The x and y arguments specify the location of the upper left + * corner of the surface relative to the upper left corner of the + * parent surface, in surface-local coordinates. + * + * The flags argument controls details of the transient behaviour. + */ +static inline void +wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TRANSIENT, parent, x, y, flags); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a fullscreen surface. + * + * If an output parameter is given then the surface will be made + * fullscreen on that output. If the client does not specify the + * output then the compositor will apply its policy - usually + * choosing the output on which the surface has the biggest surface + * area. + * + * The client may specify a method to resolve a size conflict + * between the output size and the surface size - this is provided + * through the method parameter. + * + * The framerate parameter is used only when the method is set + * to "driver", to indicate the preferred framerate. A value of 0 + * indicates that the client does not care about framerate. The + * framerate is specified in mHz, that is framerate of 60000 is 60Hz. + * + * A method of "scale" or "driver" implies a scaling operation of + * the surface, either via a direct scaling operation or a change of + * the output mode. This will override any kind of output scaling, so + * that mapping a surface with a buffer size equal to the mode can + * fill the screen independent of buffer_scale. + * + * A method of "fill" means we don't scale up the buffer, however + * any output scale is applied. This means that you may run into + * an edge case where the application maps a buffer with the same + * size of the output mode but buffer_scale 1 (thus making a + * surface larger than the output). In this case it is allowed to + * downscale the results to fit the screen. + * + * The compositor must reply to this request with a configure event + * with the dimensions for the output on which the surface will + * be made fullscreen. + */ +static inline void +wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_FULLSCREEN, method, framerate, output); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a popup. + * + * A popup surface is a transient surface with an added pointer + * grab. + * + * An existing implicit grab will be changed to owner-events mode, + * and the popup grab will continue after the implicit grab ends + * (i.e. releasing the mouse button does not cause the popup to + * be unmapped). + * + * The popup grab continues until the window is destroyed or a + * mouse button is pressed in any other client's window. A click + * in any of the client's surfaces is reported as normal, however, + * clicks in other clients' surfaces will be discarded and trigger + * the callback. + * + * The x and y arguments specify the location of the upper left + * corner of the surface relative to the upper left corner of the + * parent surface, in surface-local coordinates. + */ +static inline void +wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_POPUP, seat, serial, parent, x, y, flags); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a maximized surface. + * + * If an output parameter is given then the surface will be + * maximized on that output. If the client does not specify the + * output then the compositor will apply its policy - usually + * choosing the output on which the surface has the biggest surface + * area. + * + * The compositor will reply with a configure event telling + * the expected new surface size. The operation is completed + * on the next buffer attach to this surface. + * + * A maximized surface typically fills the entire output it is + * bound to, except for desktop elements such as panels. This is + * the main difference between a maximized shell surface and a + * fullscreen shell surface. + * + * The details depend on the compositor implementation. + */ +static inline void +wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_MAXIMIZED, output); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TITLE, title); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Set a class for the surface. + * + * The surface class identifies the general class of applications + * to which the surface belongs. A common convention is to use the + * file name (or the full path if it is a non-standard location) of + * the application's .desktop file as the class. + */ +static inline void +wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_) +{ + wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_CLASS, class_); +} + +#ifndef WL_SURFACE_ERROR_ENUM +#define WL_SURFACE_ERROR_ENUM +/** + * @ingroup iface_wl_surface + * wl_surface error values + * + * These errors can be emitted in response to wl_surface requests. + */ +enum wl_surface_error { + /** + * buffer scale value is invalid + */ + WL_SURFACE_ERROR_INVALID_SCALE = 0, + /** + * buffer transform value is invalid + */ + WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, +}; +#endif /* WL_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_surface + * @struct wl_surface_listener + */ +struct wl_surface_listener { + /** + * surface enters an output + * + * This is emitted whenever a surface's creation, movement, or + * resizing results in some part of it being within the scanout + * region of an output. + * + * Note that a surface may be overlapping with zero or more + * outputs. + * @param output output entered by the surface + */ + void (*enter)(void *data, + struct wl_surface *wl_surface, + struct wl_output *output); + /** + * surface leaves an output + * + * This is emitted whenever a surface's creation, movement, or + * resizing results in it no longer having any part of it within + * the scanout region of an output. + * @param output output left by the surface + */ + void (*leave)(void *data, + struct wl_surface *wl_surface, + struct wl_output *output); +}; + +/** + * @ingroup iface_wl_surface + */ +static inline int +wl_surface_add_listener(struct wl_surface *wl_surface, + const struct wl_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_surface, + (void (**)(void)) listener, data); +} + +#define WL_SURFACE_DESTROY 0 +#define WL_SURFACE_ATTACH 1 +#define WL_SURFACE_DAMAGE 2 +#define WL_SURFACE_FRAME 3 +#define WL_SURFACE_SET_OPAQUE_REGION 4 +#define WL_SURFACE_SET_INPUT_REGION 5 +#define WL_SURFACE_COMMIT 6 +#define WL_SURFACE_SET_BUFFER_TRANSFORM 7 +#define WL_SURFACE_SET_BUFFER_SCALE 8 +#define WL_SURFACE_DAMAGE_BUFFER 9 + +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_LEAVE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_ATTACH_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DAMAGE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_FRAME_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_COMMIT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 + +/** @ingroup iface_wl_surface */ +static inline void +wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data); +} + +/** @ingroup iface_wl_surface */ +static inline void * +wl_surface_get_user_data(struct wl_surface *wl_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_surface); +} + +static inline uint32_t +wl_surface_get_version(struct wl_surface *wl_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_surface); +} + +/** + * @ingroup iface_wl_surface + * + * Deletes the surface and invalidates its object ID. + */ +static inline void +wl_surface_destroy(struct wl_surface *wl_surface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_surface); +} + +/** + * @ingroup iface_wl_surface + * + * Set a buffer as the content of this surface. + * + * The new size of the surface is calculated based on the buffer + * size transformed by the inverse buffer_transform and the + * inverse buffer_scale. This means that the supplied buffer + * must be an integer multiple of the buffer_scale. + * + * The x and y arguments specify the location of the new pending + * buffer's upper left corner, relative to the current buffer's upper + * left corner, in surface-local coordinates. In other words, the + * x and y, combined with the new surface size define in which + * directions the surface's size changes. + * + * Surface contents are double-buffered state, see wl_surface.commit. + * + * The initial surface contents are void; there is no content. + * wl_surface.attach assigns the given wl_buffer as the pending + * wl_buffer. wl_surface.commit makes the pending wl_buffer the new + * surface contents, and the size of the surface becomes the size + * calculated from the wl_buffer, as described above. After commit, + * there is no pending buffer until the next attach. + * + * Committing a pending wl_buffer allows the compositor to read the + * pixels in the wl_buffer. The compositor may access the pixels at + * any time after the wl_surface.commit request. When the compositor + * will not access the pixels anymore, it will send the + * wl_buffer.release event. Only after receiving wl_buffer.release, + * the client may reuse the wl_buffer. A wl_buffer that has been + * attached and then replaced by another attach instead of committed + * will not receive a release event, and is not used by the + * compositor. + * + * Destroying the wl_buffer after wl_buffer.release does not change + * the surface contents. However, if the client destroys the + * wl_buffer before receiving the wl_buffer.release event, the surface + * contents become undefined immediately. + * + * If wl_surface.attach is sent with a NULL wl_buffer, the + * following wl_surface.commit will remove the surface content. + */ +static inline void +wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_ATTACH, buffer, x, y); +} + +/** + * @ingroup iface_wl_surface + * + * This request is used to describe the regions where the pending + * buffer is different from the current surface contents, and where + * the surface therefore needs to be repainted. The compositor + * ignores the parts of the damage that fall outside of the surface. + * + * Damage is double-buffered state, see wl_surface.commit. + * + * The damage rectangle is specified in surface-local coordinates, + * where x and y specify the upper left corner of the damage rectangle. + * + * The initial value for pending damage is empty: no damage. + * wl_surface.damage adds pending damage: the new pending damage + * is the union of old pending damage and the given rectangle. + * + * wl_surface.commit assigns pending damage as the current damage, + * and clears pending damage. The server will clear the current + * damage as it repaints the surface. + * + * Alternatively, damage can be posted with wl_surface.damage_buffer + * which uses buffer coordinates instead of surface coordinates, + * and is probably the preferred and intuitive way of doing this. + */ +static inline void +wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE, x, y, width, height); +} + +/** + * @ingroup iface_wl_surface + * + * Request a notification when it is a good time to start drawing a new + * frame, by creating a frame callback. This is useful for throttling + * redrawing operations, and driving animations. + * + * When a client is animating on a wl_surface, it can use the 'frame' + * request to get notified when it is a good time to draw and commit the + * next frame of animation. If the client commits an update earlier than + * that, it is likely that some updates will not make it to the display, + * and the client is wasting resources by drawing too often. + * + * The frame request will take effect on the next wl_surface.commit. + * The notification will only be posted for one frame unless + * requested again. For a wl_surface, the notifications are posted in + * the order the frame requests were committed. + * + * The server must send the notifications so that a client + * will not send excessive updates, while still allowing + * the highest possible update rate for clients that wait for the reply + * before drawing again. The server should give some time for the client + * to draw and commit after sending the frame callback events to let it + * hit the next output refresh. + * + * A server should avoid signaling the frame callbacks if the + * surface is not visible in any way, e.g. the surface is off-screen, + * or completely obscured by other opaque surfaces. + * + * The object returned by this request will be destroyed by the + * compositor after the callback is fired and as such the client must not + * attempt to use it after that point. + * + * The callback_data passed in the callback is the current time, in + * milliseconds, with an undefined base. + */ +static inline struct wl_callback * +wl_surface_frame(struct wl_surface *wl_surface) +{ + struct wl_proxy *callback; + + callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_surface, + WL_SURFACE_FRAME, &wl_callback_interface, NULL); + + return (struct wl_callback *) callback; +} + +/** + * @ingroup iface_wl_surface + * + * This request sets the region of the surface that contains + * opaque content. + * + * The opaque region is an optimization hint for the compositor + * that lets it optimize the redrawing of content behind opaque + * regions. Setting an opaque region is not required for correct + * behaviour, but marking transparent content as opaque will result + * in repaint artifacts. + * + * The opaque region is specified in surface-local coordinates. + * + * The compositor ignores the parts of the opaque region that fall + * outside of the surface. + * + * Opaque region is double-buffered state, see wl_surface.commit. + * + * wl_surface.set_opaque_region changes the pending opaque region. + * wl_surface.commit copies the pending region to the current region. + * Otherwise, the pending and current regions are never changed. + * + * The initial value for an opaque region is empty. Setting the pending + * opaque region has copy semantics, and the wl_region object can be + * destroyed immediately. A NULL wl_region causes the pending opaque + * region to be set to empty. + */ +static inline void +wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, region); +} + +/** + * @ingroup iface_wl_surface + * + * This request sets the region of the surface that can receive + * pointer and touch events. + * + * Input events happening outside of this region will try the next + * surface in the server surface stack. The compositor ignores the + * parts of the input region that fall outside of the surface. + * + * The input region is specified in surface-local coordinates. + * + * Input region is double-buffered state, see wl_surface.commit. + * + * wl_surface.set_input_region changes the pending input region. + * wl_surface.commit copies the pending region to the current region. + * Otherwise the pending and current regions are never changed, + * except cursor and icon surfaces are special cases, see + * wl_pointer.set_cursor and wl_data_device.start_drag. + * + * The initial value for an input region is infinite. That means the + * whole surface will accept input. Setting the pending input region + * has copy semantics, and the wl_region object can be destroyed + * immediately. A NULL wl_region causes the input region to be set + * to infinite. + */ +static inline void +wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_INPUT_REGION, region); +} + +/** + * @ingroup iface_wl_surface + * + * Surface state (input, opaque, and damage regions, attached buffers, + * etc.) is double-buffered. Protocol requests modify the pending state, + * as opposed to the current state in use by the compositor. A commit + * request atomically applies all pending state, replacing the current + * state. After commit, the new pending state is as documented for each + * related request. + * + * On commit, a pending wl_buffer is applied first, and all other state + * second. This means that all coordinates in double-buffered state are + * relative to the new wl_buffer coming into use, except for + * wl_surface.attach itself. If there is no pending wl_buffer, the + * coordinates are relative to the current surface contents. + * + * All requests that need a commit to become effective are documented + * to affect double-buffered state. + * + * Other interfaces may add further double-buffered surface state. + */ +static inline void +wl_surface_commit(struct wl_surface *wl_surface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_COMMIT); +} + +/** + * @ingroup iface_wl_surface + * + * This request sets an optional transformation on how the compositor + * interprets the contents of the buffer attached to the surface. The + * accepted values for the transform parameter are the values for + * wl_output.transform. + * + * Buffer transform is double-buffered state, see wl_surface.commit. + * + * A newly created surface has its buffer transformation set to normal. + * + * wl_surface.set_buffer_transform changes the pending buffer + * transformation. wl_surface.commit copies the pending buffer + * transformation to the current one. Otherwise, the pending and current + * values are never changed. + * + * The purpose of this request is to allow clients to render content + * according to the output transform, thus permitting the compositor to + * use certain optimizations even if the display is rotated. Using + * hardware overlays and scanning out a client buffer for fullscreen + * surfaces are examples of such optimizations. Those optimizations are + * highly dependent on the compositor implementation, so the use of this + * request should be considered on a case-by-case basis. + * + * Note that if the transform value includes 90 or 270 degree rotation, + * the width of the buffer will become the surface height and the height + * of the buffer will become the surface width. + * + * If transform is not one of the values from the + * wl_output.transform enum the invalid_transform protocol error + * is raised. + */ +static inline void +wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_BUFFER_TRANSFORM, transform); +} + +/** + * @ingroup iface_wl_surface + * + * This request sets an optional scaling factor on how the compositor + * interprets the contents of the buffer attached to the window. + * + * Buffer scale is double-buffered state, see wl_surface.commit. + * + * A newly created surface has its buffer scale set to 1. + * + * wl_surface.set_buffer_scale changes the pending buffer scale. + * wl_surface.commit copies the pending buffer scale to the current one. + * Otherwise, the pending and current values are never changed. + * + * The purpose of this request is to allow clients to supply higher + * resolution buffer data for use on high resolution outputs. It is + * intended that you pick the same buffer scale as the scale of the + * output that the surface is displayed on. This means the compositor + * can avoid scaling when rendering the surface on that output. + * + * Note that if the scale is larger than 1, then you have to attach + * a buffer that is larger (by a factor of scale in each dimension) + * than the desired surface size. + * + * If scale is not positive the invalid_scale protocol error is + * raised. + */ +static inline void +wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_BUFFER_SCALE, scale); +} + +/** + * @ingroup iface_wl_surface + * + * This request is used to describe the regions where the pending + * buffer is different from the current surface contents, and where + * the surface therefore needs to be repainted. The compositor + * ignores the parts of the damage that fall outside of the surface. + * + * Damage is double-buffered state, see wl_surface.commit. + * + * The damage rectangle is specified in buffer coordinates, + * where x and y specify the upper left corner of the damage rectangle. + * + * The initial value for pending damage is empty: no damage. + * wl_surface.damage_buffer adds pending damage: the new pending + * damage is the union of old pending damage and the given rectangle. + * + * wl_surface.commit assigns pending damage as the current damage, + * and clears pending damage. The server will clear the current + * damage as it repaints the surface. + * + * This request differs from wl_surface.damage in only one way - it + * takes damage in buffer coordinates instead of surface-local + * coordinates. While this generally is more intuitive than surface + * coordinates, it is especially desirable when using wp_viewport + * or when a drawing library (like EGL) is unaware of buffer scale + * and buffer transform. + * + * Note: Because buffer transformation changes and damage requests may + * be interleaved in the protocol stream, it is impossible to determine + * the actual mapping between surface and buffer damage until + * wl_surface.commit time. Therefore, compositors wishing to take both + * kinds of damage into account will have to accumulate damage from the + * two requests separately and only transform from one to the other + * after receiving the wl_surface.commit. + */ +static inline void +wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE_BUFFER, x, y, width, height); +} + +#ifndef WL_SEAT_CAPABILITY_ENUM +#define WL_SEAT_CAPABILITY_ENUM +/** + * @ingroup iface_wl_seat + * seat capability bitmask + * + * This is a bitmask of capabilities this seat has; if a member is + * set, then it is present on the seat. + */ +enum wl_seat_capability { + /** + * the seat has pointer devices + */ + WL_SEAT_CAPABILITY_POINTER = 1, + /** + * the seat has one or more keyboards + */ + WL_SEAT_CAPABILITY_KEYBOARD = 2, + /** + * the seat has touch devices + */ + WL_SEAT_CAPABILITY_TOUCH = 4, +}; +#endif /* WL_SEAT_CAPABILITY_ENUM */ + +/** + * @ingroup iface_wl_seat + * @struct wl_seat_listener + */ +struct wl_seat_listener { + /** + * seat capabilities changed + * + * This is emitted whenever a seat gains or loses the pointer, + * keyboard or touch capabilities. The argument is a capability + * enum containing the complete set of capabilities this seat has. + * + * When the pointer capability is added, a client may create a + * wl_pointer object using the wl_seat.get_pointer request. This + * object will receive pointer events until the capability is + * removed in the future. + * + * When the pointer capability is removed, a client should destroy + * the wl_pointer objects associated with the seat where the + * capability was removed, using the wl_pointer.release request. No + * further pointer events will be received on these objects. + * + * In some compositors, if a seat regains the pointer capability + * and a client has a previously obtained wl_pointer object of + * version 4 or less, that object may start sending pointer events + * again. This behavior is considered a misinterpretation of the + * intended behavior and must not be relied upon by the client. + * wl_pointer objects of version 5 or later must not send events if + * created before the most recent event notifying the client of an + * added pointer capability. + * + * The above behavior also applies to wl_keyboard and wl_touch with + * the keyboard and touch capabilities, respectively. + * @param capabilities capabilities of the seat + */ + void (*capabilities)(void *data, + struct wl_seat *wl_seat, + uint32_t capabilities); + /** + * unique identifier for this seat + * + * In a multiseat configuration this can be used by the client to + * help identify which physical devices the seat represents. Based + * on the seat configuration used by the compositor. + * @param name seat identifier + * @since 2 + */ + void (*name)(void *data, + struct wl_seat *wl_seat, + const char *name); +}; + +/** + * @ingroup iface_wl_seat + */ +static inline int +wl_seat_add_listener(struct wl_seat *wl_seat, + const struct wl_seat_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_seat, + (void (**)(void)) listener, data); +} + +#define WL_SEAT_GET_POINTER 0 +#define WL_SEAT_GET_KEYBOARD 1 +#define WL_SEAT_GET_TOUCH 2 +#define WL_SEAT_RELEASE 3 + +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_NAME_SINCE_VERSION 2 + +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_POINTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_RELEASE_SINCE_VERSION 5 + +/** @ingroup iface_wl_seat */ +static inline void +wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data); +} + +/** @ingroup iface_wl_seat */ +static inline void * +wl_seat_get_user_data(struct wl_seat *wl_seat) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_seat); +} + +static inline uint32_t +wl_seat_get_version(struct wl_seat *wl_seat) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_seat); +} + +/** @ingroup iface_wl_seat */ +static inline void +wl_seat_destroy(struct wl_seat *wl_seat) +{ + wl_proxy_destroy((struct wl_proxy *) wl_seat); +} + +/** + * @ingroup iface_wl_seat + * + * The ID provided will be initialized to the wl_pointer interface + * for this seat. + * + * This request only takes effect if the seat has the pointer + * capability, or has had the pointer capability in the past. + * It is a protocol violation to issue this request on a seat that has + * never had the pointer capability. + */ +static inline struct wl_pointer * +wl_seat_get_pointer(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat, + WL_SEAT_GET_POINTER, &wl_pointer_interface, NULL); + + return (struct wl_pointer *) id; +} + +/** + * @ingroup iface_wl_seat + * + * The ID provided will be initialized to the wl_keyboard interface + * for this seat. + * + * This request only takes effect if the seat has the keyboard + * capability, or has had the keyboard capability in the past. + * It is a protocol violation to issue this request on a seat that has + * never had the keyboard capability. + */ +static inline struct wl_keyboard * +wl_seat_get_keyboard(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat, + WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, NULL); + + return (struct wl_keyboard *) id; +} + +/** + * @ingroup iface_wl_seat + * + * The ID provided will be initialized to the wl_touch interface + * for this seat. + * + * This request only takes effect if the seat has the touch + * capability, or has had the touch capability in the past. + * It is a protocol violation to issue this request on a seat that has + * never had the touch capability. + */ +static inline struct wl_touch * +wl_seat_get_touch(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat, + WL_SEAT_GET_TOUCH, &wl_touch_interface, NULL); + + return (struct wl_touch *) id; +} + +/** + * @ingroup iface_wl_seat + * + * Using this request a client can tell the server that it is not going to + * use the seat object anymore. + */ +static inline void +wl_seat_release(struct wl_seat *wl_seat) +{ + wl_proxy_marshal((struct wl_proxy *) wl_seat, + WL_SEAT_RELEASE); + + wl_proxy_destroy((struct wl_proxy *) wl_seat); +} + +#ifndef WL_POINTER_ERROR_ENUM +#define WL_POINTER_ERROR_ENUM +enum wl_pointer_error { + /** + * given wl_surface has another role + */ + WL_POINTER_ERROR_ROLE = 0, +}; +#endif /* WL_POINTER_ERROR_ENUM */ + +#ifndef WL_POINTER_BUTTON_STATE_ENUM +#define WL_POINTER_BUTTON_STATE_ENUM +/** + * @ingroup iface_wl_pointer + * physical button state + * + * Describes the physical state of a button that produced the button + * event. + */ +enum wl_pointer_button_state { + /** + * the button is not pressed + */ + WL_POINTER_BUTTON_STATE_RELEASED = 0, + /** + * the button is pressed + */ + WL_POINTER_BUTTON_STATE_PRESSED = 1, +}; +#endif /* WL_POINTER_BUTTON_STATE_ENUM */ + +#ifndef WL_POINTER_AXIS_ENUM +#define WL_POINTER_AXIS_ENUM +/** + * @ingroup iface_wl_pointer + * axis types + * + * Describes the axis types of scroll events. + */ +enum wl_pointer_axis { + /** + * vertical axis + */ + WL_POINTER_AXIS_VERTICAL_SCROLL = 0, + /** + * horizontal axis + */ + WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, +}; +#endif /* WL_POINTER_AXIS_ENUM */ + +#ifndef WL_POINTER_AXIS_SOURCE_ENUM +#define WL_POINTER_AXIS_SOURCE_ENUM +/** + * @ingroup iface_wl_pointer + * axis source types + * + * Describes the source types for axis events. This indicates to the + * client how an axis event was physically generated; a client may + * adjust the user interface accordingly. For example, scroll events + * from a "finger" source may be in a smooth coordinate space with + * kinetic scrolling whereas a "wheel" source may be in discrete steps + * of a number of lines. + * + * The "continuous" axis source is a device generating events in a + * continuous coordinate space, but using something other than a + * finger. One example for this source is button-based scrolling where + * the vertical motion of a device is converted to scroll events while + * a button is held down. + */ +enum wl_pointer_axis_source { + /** + * a physical wheel + */ + WL_POINTER_AXIS_SOURCE_WHEEL = 0, + /** + * finger on a touch surface + */ + WL_POINTER_AXIS_SOURCE_FINGER = 1, + /** + * continuous coordinate space + */ + WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, +}; +#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ + +/** + * @ingroup iface_wl_pointer + * @struct wl_pointer_listener + */ +struct wl_pointer_listener { + /** + * enter event + * + * Notification that this seat's pointer is focused on a certain + * surface. + * + * When a seat's focus enters a surface, the pointer image is + * undefined and a client should respond to this event by setting + * an appropriate pointer image with the set_cursor request. + * @param serial serial number of the enter event + * @param surface surface entered by the pointer + * @param surface_x surface-local x coordinate + * @param surface_y surface-local y coordinate + */ + void (*enter)(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y); + /** + * leave event + * + * Notification that this seat's pointer is no longer focused on + * a certain surface. + * + * The leave notification is sent before the enter notification for + * the new focus. + * @param serial serial number of the leave event + * @param surface surface left by the pointer + */ + void (*leave)(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface); + /** + * pointer motion event + * + * Notification of pointer location change. The arguments + * surface_x and surface_y are the location relative to the focused + * surface. + * @param time timestamp with millisecond granularity + * @param surface_x surface-local x coordinate + * @param surface_y surface-local y coordinate + */ + void (*motion)(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y); + /** + * pointer button event + * + * Mouse button click and release notifications. + * + * The location of the click is given by the last motion or enter + * event. The time argument is a timestamp with millisecond + * granularity, with an undefined base. + * @param serial serial number of the button event + * @param time timestamp with millisecond granularity + * @param button button that produced the event + * @param state physical state of the button + */ + void (*button)(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state); + /** + * axis event + * + * Scroll and other axis notifications. + * + * For scroll events (vertical and horizontal scroll axes), the + * value parameter is the length of a vector along the specified + * axis in a coordinate space identical to those of motion events, + * representing a relative movement along the specified axis. + * + * For devices that support movements non-parallel to axes multiple + * axis events will be emitted. + * + * When applicable, for example for touch pads, the server can + * choose to emit scroll events where the motion vector is + * equivalent to a motion event vector. + * + * When applicable, a client can transform its content relative to + * the scroll distance. + * @param time timestamp with millisecond granularity + * @param axis axis type + * @param value length of vector in surface-local coordinate space + */ + void (*axis)(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value); + /** + * end of a pointer event sequence + * + * Indicates the end of a set of events that logically belong + * together. A client is expected to accumulate the data in all + * events within the frame before proceeding. + * + * All wl_pointer events before a wl_pointer.frame event belong + * logically together. For example, in a diagonal scroll motion the + * compositor will send an optional wl_pointer.axis_source event, + * two wl_pointer.axis events (horizontal and vertical) and finally + * a wl_pointer.frame event. The client may use this information to + * calculate a diagonal vector for scrolling. + * + * When multiple wl_pointer.axis events occur within the same + * frame, the motion vector is the combined motion of all events. + * When a wl_pointer.axis and a wl_pointer.axis_stop event occur + * within the same frame, this indicates that axis movement in one + * axis has stopped but continues in the other axis. When multiple + * wl_pointer.axis_stop events occur within the same frame, this + * indicates that these axes stopped in the same instance. + * + * A wl_pointer.frame event is sent for every logical event group, + * even if the group only contains a single wl_pointer event. + * Specifically, a client may get a sequence: motion, frame, + * button, frame, axis, frame, axis_stop, frame. + * + * The wl_pointer.enter and wl_pointer.leave events are logical + * events generated by the compositor and not the hardware. These + * events are also grouped by a wl_pointer.frame. When a pointer + * moves from one surface to another, a compositor should group the + * wl_pointer.leave event within the same wl_pointer.frame. + * However, a client must not rely on wl_pointer.leave and + * wl_pointer.enter being in the same wl_pointer.frame. + * Compositor-specific policies may require the wl_pointer.leave + * and wl_pointer.enter event being split across multiple + * wl_pointer.frame groups. + * @since 5 + */ + void (*frame)(void *data, + struct wl_pointer *wl_pointer); + /** + * axis source event + * + * Source information for scroll and other axes. + * + * This event does not occur on its own. It is sent before a + * wl_pointer.frame event and carries the source information for + * all events within that frame. + * + * The source specifies how this event was generated. If the source + * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event + * will be sent when the user lifts the finger off the device. + * + * If the source is wl_pointer axis_source.wheel or + * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event + * may or may not be sent. Whether a compositor sends an axis_stop + * event for these sources is hardware-specific and + * implementation-dependent; clients must not rely on receiving an + * axis_stop event for these scroll sources and should treat scroll + * sequences from these scroll sources as unterminated by default. + * + * This event is optional. If the source is unknown for a + * particular axis event sequence, no event is sent. Only one + * wl_pointer.axis_source event is permitted per frame. + * + * The order of wl_pointer.axis_discrete and wl_pointer.axis_source + * is not guaranteed. + * @param axis_source source of the axis event + * @since 5 + */ + void (*axis_source)(void *data, + struct wl_pointer *wl_pointer, + uint32_t axis_source); + /** + * axis stop event + * + * Stop notification for scroll and other axes. + * + * For some wl_pointer.axis_source types, a wl_pointer.axis_stop + * event is sent to notify a client that the axis sequence has + * terminated. This enables the client to implement kinetic + * scrolling. See the wl_pointer.axis_source documentation for + * information on when this event may be generated. + * + * Any wl_pointer.axis events with the same axis_source after this + * event should be considered as the start of a new axis motion. + * + * The timestamp is to be interpreted identical to the timestamp in + * the wl_pointer.axis event. The timestamp value may be the same + * as a preceding wl_pointer.axis event. + * @param time timestamp with millisecond granularity + * @param axis the axis stopped with this event + * @since 5 + */ + void (*axis_stop)(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + uint32_t axis); + /** + * axis click event + * + * Discrete step information for scroll and other axes. + * + * This event carries the axis value of the wl_pointer.axis event + * in discrete steps (e.g. mouse wheel clicks). + * + * This event does not occur on its own, it is coupled with a + * wl_pointer.axis event that represents this axis value on a + * continuous scale. The protocol guarantees that each + * axis_discrete event is always followed by exactly one axis event + * with the same axis number within the same wl_pointer.frame. Note + * that the protocol allows for other events to occur between the + * axis_discrete and its coupled axis event, including other + * axis_discrete or axis events. + * + * This event is optional; continuous scrolling devices like + * two-finger scrolling on touchpads do not have discrete steps and + * do not generate this event. + * + * The discrete value carries the directional information. e.g. a + * value of -2 is two steps towards the negative direction of this + * axis. + * + * The axis number is identical to the axis number in the + * associated axis event. + * + * The order of wl_pointer.axis_discrete and wl_pointer.axis_source + * is not guaranteed. + * @param axis axis type + * @param discrete number of steps + * @since 5 + */ + void (*axis_discrete)(void *data, + struct wl_pointer *wl_pointer, + uint32_t axis, + int32_t discrete); +}; + +/** + * @ingroup iface_wl_pointer + */ +static inline int +wl_pointer_add_listener(struct wl_pointer *wl_pointer, + const struct wl_pointer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_pointer, + (void (**)(void)) listener, data); +} + +#define WL_POINTER_SET_CURSOR 0 +#define WL_POINTER_RELEASE 1 + +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_FRAME_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 + +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_pointer */ +static inline void +wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data); +} + +/** @ingroup iface_wl_pointer */ +static inline void * +wl_pointer_get_user_data(struct wl_pointer *wl_pointer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer); +} + +static inline uint32_t +wl_pointer_get_version(struct wl_pointer *wl_pointer) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_pointer); +} + +/** @ingroup iface_wl_pointer */ +static inline void +wl_pointer_destroy(struct wl_pointer *wl_pointer) +{ + wl_proxy_destroy((struct wl_proxy *) wl_pointer); +} + +/** + * @ingroup iface_wl_pointer + * + * Set the pointer surface, i.e., the surface that contains the + * pointer image (cursor). This request gives the surface the role + * of a cursor. If the surface already has another role, it raises + * a protocol error. + * + * The cursor actually changes only if the pointer + * focus for this device is one of the requesting client's surfaces + * or the surface parameter is the current pointer surface. If + * there was a previous surface set with this request it is + * replaced. If surface is NULL, the pointer image is hidden. + * + * The parameters hotspot_x and hotspot_y define the position of + * the pointer surface relative to the pointer location. Its + * top-left corner is always at (x, y) - (hotspot_x, hotspot_y), + * where (x, y) are the coordinates of the pointer location, in + * surface-local coordinates. + * + * On surface.attach requests to the pointer surface, hotspot_x + * and hotspot_y are decremented by the x and y parameters + * passed to the request. Attach must be confirmed by + * wl_surface.commit as usual. + * + * The hotspot can also be updated by passing the currently set + * pointer surface to this request with new values for hotspot_x + * and hotspot_y. + * + * The current and pending input regions of the wl_surface are + * cleared, and wl_surface.set_input_region is ignored until the + * wl_surface is no longer used as the cursor. When the use as a + * cursor ends, the current and pending input regions become + * undefined, and the wl_surface is unmapped. + */ +static inline void +wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) +{ + wl_proxy_marshal((struct wl_proxy *) wl_pointer, + WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y); +} + +/** + * @ingroup iface_wl_pointer + * + * Using this request a client can tell the server that it is not going to + * use the pointer object anymore. + * + * This request destroys the pointer proxy object, so clients must not call + * wl_pointer_destroy() after using this request. + */ +static inline void +wl_pointer_release(struct wl_pointer *wl_pointer) +{ + wl_proxy_marshal((struct wl_proxy *) wl_pointer, + WL_POINTER_RELEASE); + + wl_proxy_destroy((struct wl_proxy *) wl_pointer); +} + +#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM +#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM +/** + * @ingroup iface_wl_keyboard + * keyboard mapping format + * + * This specifies the format of the keymap provided to the + * client with the wl_keyboard.keymap event. + */ +enum wl_keyboard_keymap_format { + /** + * no keymap; client must understand how to interpret the raw keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, + /** + * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, +}; +#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ + +#ifndef WL_KEYBOARD_KEY_STATE_ENUM +#define WL_KEYBOARD_KEY_STATE_ENUM +/** + * @ingroup iface_wl_keyboard + * physical key state + * + * Describes the physical state of a key that produced the key event. + */ +enum wl_keyboard_key_state { + /** + * key is not pressed + */ + WL_KEYBOARD_KEY_STATE_RELEASED = 0, + /** + * key is pressed + */ + WL_KEYBOARD_KEY_STATE_PRESSED = 1, +}; +#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ + +/** + * @ingroup iface_wl_keyboard + * @struct wl_keyboard_listener + */ +struct wl_keyboard_listener { + /** + * keyboard mapping + * + * This event provides a file descriptor to the client which can + * be memory-mapped to provide a keyboard mapping description. + * @param format keymap format + * @param fd keymap file descriptor + * @param size keymap size, in bytes + */ + void (*keymap)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t format, + int32_t fd, + uint32_t size); + /** + * enter event + * + * Notification that this seat's keyboard focus is on a certain + * surface. + * @param serial serial number of the enter event + * @param surface surface gaining keyboard focus + * @param keys the currently pressed keys + */ + void (*enter)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + struct wl_surface *surface, + struct wl_array *keys); + /** + * leave event + * + * Notification that this seat's keyboard focus is no longer on a + * certain surface. + * + * The leave notification is sent before the enter notification for + * the new focus. + * @param serial serial number of the leave event + * @param surface surface that lost keyboard focus + */ + void (*leave)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + struct wl_surface *surface); + /** + * key event + * + * A key was pressed or released. The time argument is a + * timestamp with millisecond granularity, with an undefined base. + * @param serial serial number of the key event + * @param time timestamp with millisecond granularity + * @param key key that produced the event + * @param state physical state of the key + */ + void (*key)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state); + /** + * modifier and group state + * + * Notifies clients that the modifier and/or group state has + * changed, and it should update its local state. + * @param serial serial number of the modifiers event + * @param mods_depressed depressed modifiers + * @param mods_latched latched modifiers + * @param mods_locked locked modifiers + * @param group keyboard layout + */ + void (*modifiers)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group); + /** + * repeat rate and delay + * + * Informs the client about the keyboard's repeat rate and delay. + * + * This event is sent as soon as the wl_keyboard object has been + * created, and is guaranteed to be received by the client before + * any key press event. + * + * Negative values for either rate or delay are illegal. A rate of + * zero will disable any repeating (regardless of the value of + * delay). + * + * This event can be sent later on as well with a new value if + * necessary, so clients should continue listening for the event + * past the creation of wl_keyboard. + * @param rate the rate of repeating keys in characters per second + * @param delay delay in milliseconds since key down until repeating starts + * @since 4 + */ + void (*repeat_info)(void *data, + struct wl_keyboard *wl_keyboard, + int32_t rate, + int32_t delay); +}; + +/** + * @ingroup iface_wl_keyboard + */ +static inline int +wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard, + const struct wl_keyboard_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard, + (void (**)(void)) listener, data); +} + +#define WL_KEYBOARD_RELEASE 0 + +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_KEY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 + +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_keyboard */ +static inline void +wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data); +} + +/** @ingroup iface_wl_keyboard */ +static inline void * +wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard); +} + +static inline uint32_t +wl_keyboard_get_version(struct wl_keyboard *wl_keyboard) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_keyboard); +} + +/** @ingroup iface_wl_keyboard */ +static inline void +wl_keyboard_destroy(struct wl_keyboard *wl_keyboard) +{ + wl_proxy_destroy((struct wl_proxy *) wl_keyboard); +} + +/** + * @ingroup iface_wl_keyboard + */ +static inline void +wl_keyboard_release(struct wl_keyboard *wl_keyboard) +{ + wl_proxy_marshal((struct wl_proxy *) wl_keyboard, + WL_KEYBOARD_RELEASE); + + wl_proxy_destroy((struct wl_proxy *) wl_keyboard); +} + +/** + * @ingroup iface_wl_touch + * @struct wl_touch_listener + */ +struct wl_touch_listener { + /** + * touch down event and beginning of a touch sequence + * + * A new touch point has appeared on the surface. This touch + * point is assigned a unique ID. Future events from this touch + * point reference this ID. The ID ceases to be valid after a touch + * up event and may be reused in the future. + * @param serial serial number of the touch down event + * @param time timestamp with millisecond granularity + * @param surface surface touched + * @param id the unique ID of this touch point + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*down)(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y); + /** + * end of a touch event sequence + * + * The touch point has disappeared. No further events will be + * sent for this touch point and the touch point's ID is released + * and may be reused in a future touch down event. + * @param serial serial number of the touch up event + * @param time timestamp with millisecond granularity + * @param id the unique ID of this touch point + */ + void (*up)(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + int32_t id); + /** + * update of touch point coordinates + * + * A touch point has changed coordinates. + * @param time timestamp with millisecond granularity + * @param id the unique ID of this touch point + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*motion)(void *data, + struct wl_touch *wl_touch, + uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y); + /** + * end of touch frame event + * + * Indicates the end of a contact point list. + */ + void (*frame)(void *data, + struct wl_touch *wl_touch); + /** + * touch session cancelled + * + * Sent if the compositor decides the touch stream is a global + * gesture. No further events are sent to the clients from that + * particular gesture. Touch cancellation applies to all touch + * points currently active on this client's surface. The client is + * responsible for finalizing the touch points, future touch points + * on this surface may reuse the touch point ID. + */ + void (*cancel)(void *data, + struct wl_touch *wl_touch); +}; + +/** + * @ingroup iface_wl_touch + */ +static inline int +wl_touch_add_listener(struct wl_touch *wl_touch, + const struct wl_touch_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_touch, + (void (**)(void)) listener, data); +} + +#define WL_TOUCH_RELEASE 0 + +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_DOWN_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_UP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_FRAME_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_CANCEL_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_touch */ +static inline void +wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data); +} + +/** @ingroup iface_wl_touch */ +static inline void * +wl_touch_get_user_data(struct wl_touch *wl_touch) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_touch); +} + +static inline uint32_t +wl_touch_get_version(struct wl_touch *wl_touch) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_touch); +} + +/** @ingroup iface_wl_touch */ +static inline void +wl_touch_destroy(struct wl_touch *wl_touch) +{ + wl_proxy_destroy((struct wl_proxy *) wl_touch); +} + +/** + * @ingroup iface_wl_touch + */ +static inline void +wl_touch_release(struct wl_touch *wl_touch) +{ + wl_proxy_marshal((struct wl_proxy *) wl_touch, + WL_TOUCH_RELEASE); + + wl_proxy_destroy((struct wl_proxy *) wl_touch); +} + +#ifndef WL_OUTPUT_SUBPIXEL_ENUM +#define WL_OUTPUT_SUBPIXEL_ENUM +/** + * @ingroup iface_wl_output + * subpixel geometry information + * + * This enumeration describes how the physical + * pixels on an output are laid out. + */ +enum wl_output_subpixel { + /** + * unknown geometry + */ + WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, + /** + * no geometry + */ + WL_OUTPUT_SUBPIXEL_NONE = 1, + /** + * horizontal RGB + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, + /** + * horizontal BGR + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, + /** + * vertical RGB + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, + /** + * vertical BGR + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, +}; +#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ + +#ifndef WL_OUTPUT_TRANSFORM_ENUM +#define WL_OUTPUT_TRANSFORM_ENUM +/** + * @ingroup iface_wl_output + * transform from framebuffer to output + * + * This describes the transform that a compositor will apply to a + * surface to compensate for the rotation or mirroring of an + * output device. + * + * The flipped values correspond to an initial flip around a + * vertical axis followed by rotation. + * + * The purpose is mainly to allow clients to render accordingly and + * tell the compositor, so that for fullscreen surfaces, the + * compositor will still be able to scan out directly from client + * surfaces. + */ +enum wl_output_transform { + /** + * no transform + */ + WL_OUTPUT_TRANSFORM_NORMAL = 0, + /** + * 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_90 = 1, + /** + * 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_180 = 2, + /** + * 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_270 = 3, + /** + * 180 degree flip around a vertical axis + */ + WL_OUTPUT_TRANSFORM_FLIPPED = 4, + /** + * flip and rotate 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, + /** + * flip and rotate 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, + /** + * flip and rotate 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, +}; +#endif /* WL_OUTPUT_TRANSFORM_ENUM */ + +#ifndef WL_OUTPUT_MODE_ENUM +#define WL_OUTPUT_MODE_ENUM +/** + * @ingroup iface_wl_output + * mode information + * + * These flags describe properties of an output mode. + * They are used in the flags bitfield of the mode event. + */ +enum wl_output_mode { + /** + * indicates this is the current mode + */ + WL_OUTPUT_MODE_CURRENT = 0x1, + /** + * indicates this is the preferred mode + */ + WL_OUTPUT_MODE_PREFERRED = 0x2, +}; +#endif /* WL_OUTPUT_MODE_ENUM */ + +/** + * @ingroup iface_wl_output + * @struct wl_output_listener + */ +struct wl_output_listener { + /** + * properties of the output + * + * The geometry event describes geometric properties of the + * output. The event is sent when binding to the output object and + * whenever any of the properties change. + * @param x x position within the global compositor space + * @param y y position within the global compositor space + * @param physical_width width in millimeters of the output + * @param physical_height height in millimeters of the output + * @param subpixel subpixel orientation of the output + * @param make textual description of the manufacturer + * @param model textual description of the model + * @param transform transform that maps framebuffer to output + */ + void (*geometry)(void *data, + struct wl_output *wl_output, + int32_t x, + int32_t y, + int32_t physical_width, + int32_t physical_height, + int32_t subpixel, + const char *make, + const char *model, + int32_t transform); + /** + * advertise available modes for the output + * + * The mode event describes an available mode for the output. + * + * The event is sent when binding to the output object and there + * will always be one mode, the current mode. The event is sent + * again if an output changes mode, for the mode that is now + * current. In other words, the current mode is always the last + * mode that was received with the current flag set. + * + * The size of a mode is given in physical hardware units of the + * output device. This is not necessarily the same as the output + * size in the global compositor space. For instance, the output + * may be scaled, as described in wl_output.scale, or transformed, + * as described in wl_output.transform. + * @param flags bitfield of mode flags + * @param width width of the mode in hardware units + * @param height height of the mode in hardware units + * @param refresh vertical refresh rate in mHz + */ + void (*mode)(void *data, + struct wl_output *wl_output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh); + /** + * sent all information about output + * + * This event is sent after all other properties have been sent + * after binding to the output object and after any other property + * changes done after that. This allows changes to the output + * properties to be seen as atomic, even if they happen via + * multiple events. + * @since 2 + */ + void (*done)(void *data, + struct wl_output *wl_output); + /** + * output scaling properties + * + * This event contains scaling geometry information that is not + * in the geometry event. It may be sent after binding the output + * object or if the output scale changes later. If it is not sent, + * the client should assume a scale of 1. + * + * A scale larger than 1 means that the compositor will + * automatically scale surface buffers by this amount when + * rendering. This is used for very high resolution displays where + * applications rendering at the native resolution would be too + * small to be legible. + * + * It is intended that scaling aware clients track the current + * output of a surface, and if it is on a scaled output it should + * use wl_surface.set_buffer_scale with the scale of the output. + * That way the compositor can avoid scaling the surface, and the + * client can supply a higher detail image. + * @param factor scaling factor of output + * @since 2 + */ + void (*scale)(void *data, + struct wl_output *wl_output, + int32_t factor); +}; + +/** + * @ingroup iface_wl_output + */ +static inline int +wl_output_add_listener(struct wl_output *wl_output, + const struct wl_output_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_output, + (void (**)(void)) listener, data); +} + +#define WL_OUTPUT_RELEASE 0 + +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_DONE_SINCE_VERSION 2 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_SCALE_SINCE_VERSION 2 + +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_output */ +static inline void +wl_output_set_user_data(struct wl_output *wl_output, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data); +} + +/** @ingroup iface_wl_output */ +static inline void * +wl_output_get_user_data(struct wl_output *wl_output) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_output); +} + +static inline uint32_t +wl_output_get_version(struct wl_output *wl_output) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_output); +} + +/** @ingroup iface_wl_output */ +static inline void +wl_output_destroy(struct wl_output *wl_output) +{ + wl_proxy_destroy((struct wl_proxy *) wl_output); +} + +/** + * @ingroup iface_wl_output + * + * Using this request a client can tell the server that it is not going to + * use the output object anymore. + */ +static inline void +wl_output_release(struct wl_output *wl_output) +{ + wl_proxy_marshal((struct wl_proxy *) wl_output, + WL_OUTPUT_RELEASE); + + wl_proxy_destroy((struct wl_proxy *) wl_output); +} + +#define WL_REGION_DESTROY 0 +#define WL_REGION_ADD 1 +#define WL_REGION_SUBTRACT 2 + + +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_ADD_SINCE_VERSION 1 +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_SUBTRACT_SINCE_VERSION 1 + +/** @ingroup iface_wl_region */ +static inline void +wl_region_set_user_data(struct wl_region *wl_region, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data); +} + +/** @ingroup iface_wl_region */ +static inline void * +wl_region_get_user_data(struct wl_region *wl_region) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_region); +} + +static inline uint32_t +wl_region_get_version(struct wl_region *wl_region) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_region); +} + +/** + * @ingroup iface_wl_region + * + * Destroy the region. This will invalidate the object ID. + */ +static inline void +wl_region_destroy(struct wl_region *wl_region) +{ + wl_proxy_marshal((struct wl_proxy *) wl_region, + WL_REGION_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_region); +} + +/** + * @ingroup iface_wl_region + * + * Add the specified rectangle to the region. + */ +static inline void +wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wl_region, + WL_REGION_ADD, x, y, width, height); +} + +/** + * @ingroup iface_wl_region + * + * Subtract the specified rectangle from the region. + */ +static inline void +wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wl_region, + WL_REGION_SUBTRACT, x, y, width, height); +} + +#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM +#define WL_SUBCOMPOSITOR_ERROR_ENUM +enum wl_subcompositor_error { + /** + * the to-be sub-surface is invalid + */ + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ + +#define WL_SUBCOMPOSITOR_DESTROY 0 +#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1 + + +/** + * @ingroup iface_wl_subcompositor + */ +#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subcompositor + */ +#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 + +/** @ingroup iface_wl_subcompositor */ +static inline void +wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data); +} + +/** @ingroup iface_wl_subcompositor */ +static inline void * +wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor); +} + +static inline uint32_t +wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor); +} + +/** + * @ingroup iface_wl_subcompositor + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other + * objects, wl_subsurface objects included. + */ +static inline void +wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subcompositor, + WL_SUBCOMPOSITOR_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_subcompositor); +} + +/** + * @ingroup iface_wl_subcompositor + * + * Create a sub-surface interface for the given surface, and + * associate it with the given parent surface. This turns a + * plain wl_surface into a sub-surface. + * + * The to-be sub-surface must not already have another role, and it + * must not have an existing wl_subsurface object. Otherwise a protocol + * error is raised. + */ +static inline struct wl_subsurface * +wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_subcompositor, + WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, NULL, surface, parent); + + return (struct wl_subsurface *) id; +} + +#ifndef WL_SUBSURFACE_ERROR_ENUM +#define WL_SUBSURFACE_ERROR_ENUM +enum wl_subsurface_error { + /** + * wl_surface is not a sibling or the parent + */ + WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBSURFACE_ERROR_ENUM */ + +#define WL_SUBSURFACE_DESTROY 0 +#define WL_SUBSURFACE_SET_POSITION 1 +#define WL_SUBSURFACE_PLACE_ABOVE 2 +#define WL_SUBSURFACE_PLACE_BELOW 3 +#define WL_SUBSURFACE_SET_SYNC 4 +#define WL_SUBSURFACE_SET_DESYNC 5 + + +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 + +/** @ingroup iface_wl_subsurface */ +static inline void +wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data); +} + +/** @ingroup iface_wl_subsurface */ +static inline void * +wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface); +} + +static inline uint32_t +wl_subsurface_get_version(struct wl_subsurface *wl_subsurface) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_subsurface); +} + +/** + * @ingroup iface_wl_subsurface + * + * The sub-surface interface is removed from the wl_surface object + * that was turned into a sub-surface with a + * wl_subcompositor.get_subsurface request. The wl_surface's association + * to the parent is deleted, and the wl_surface loses its role as + * a sub-surface. The wl_surface is unmapped. + */ +static inline void +wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_subsurface); +} + +/** + * @ingroup iface_wl_subsurface + * + * This schedules a sub-surface position change. + * The sub-surface will be moved so that its origin (top left + * corner pixel) will be at the location x, y of the parent surface + * coordinate system. The coordinates are not restricted to the parent + * surface area. Negative values are allowed. + * + * The scheduled coordinates will take effect whenever the state of the + * parent surface is applied. When this happens depends on whether the + * parent surface is in synchronized mode or not. See + * wl_subsurface.set_sync and wl_subsurface.set_desync for details. + * + * If more than one set_position request is invoked by the client before + * the commit of the parent surface, the position of a new request always + * replaces the scheduled position from any previous request. + * + * The initial position is 0, 0. + */ +static inline void +wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_POSITION, x, y); +} + +/** + * @ingroup iface_wl_subsurface + * + * This sub-surface is taken from the stack, and put back just + * above the reference surface, changing the z-order of the sub-surfaces. + * The reference surface must be one of the sibling surfaces, or the + * parent surface. Using any other surface, including this sub-surface, + * will cause a protocol error. + * + * The z-order is double-buffered. Requests are handled in order and + * applied immediately to a pending state. The final pending state is + * copied to the active state the next time the state of the parent + * surface is applied. When this happens depends on whether the parent + * surface is in synchronized mode or not. See wl_subsurface.set_sync and + * wl_subsurface.set_desync for details. + * + * A new sub-surface is initially added as the top-most in the stack + * of its siblings and parent. + */ +static inline void +wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_PLACE_ABOVE, sibling); +} + +/** + * @ingroup iface_wl_subsurface + * + * The sub-surface is placed just below the reference surface. + * See wl_subsurface.place_above. + */ +static inline void +wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_PLACE_BELOW, sibling); +} + +/** + * @ingroup iface_wl_subsurface + * + * Change the commit behaviour of the sub-surface to synchronized + * mode, also described as the parent dependent mode. + * + * In synchronized mode, wl_surface.commit on a sub-surface will + * accumulate the committed state in a cache, but the state will + * not be applied and hence will not change the compositor output. + * The cached state is applied to the sub-surface immediately after + * the parent surface's state is applied. This ensures atomic + * updates of the parent and all its synchronized sub-surfaces. + * Applying the cached state will invalidate the cache, so further + * parent surface commits do not (re-)apply old state. + * + * See wl_subsurface for the recursive effect of this mode. + */ +static inline void +wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_SYNC); +} + +/** + * @ingroup iface_wl_subsurface + * + * Change the commit behaviour of the sub-surface to desynchronized + * mode, also described as independent or freely running mode. + * + * In desynchronized mode, wl_surface.commit on a sub-surface will + * apply the pending state directly, without caching, as happens + * normally with a wl_surface. Calling wl_surface.commit on the + * parent surface has no effect on the sub-surface's wl_surface + * state. This mode allows a sub-surface to be updated on its own. + * + * If cached state exists when wl_surface.commit is called in + * desynchronized mode, the pending state is added to the cached + * state, and applied as a whole. This invalidates the cache. + * + * Note: even if a sub-surface is set to desynchronized, a parent + * sub-surface may override it to behave as synchronized. For details, + * see wl_subsurface. + * + * If a surface's parent surface behaves as desynchronized, then + * the cached state is applied on set_desync. + */ +static inline void +wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_DESYNC); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/example-code.c b/tests/data/example-code.c new file mode 100644 index 00000000..7dea253c --- /dev/null +++ b/tests/data/example-code.c @@ -0,0 +1,505 @@ +/* SCANNER TEST */ + +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2010-2011 Intel Corporation + * Copyright © 2012-2013 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_buffer_interface; +extern const struct wl_interface wl_callback_interface; +extern const struct wl_interface wl_data_device_interface; +extern const struct wl_interface wl_data_offer_interface; +extern const struct wl_interface wl_data_source_interface; +extern const struct wl_interface wl_keyboard_interface; +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_pointer_interface; +extern const struct wl_interface wl_region_interface; +extern const struct wl_interface wl_registry_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_shell_surface_interface; +extern const struct wl_interface wl_shm_pool_interface; +extern const struct wl_interface wl_subsurface_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_touch_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_callback_interface, + &wl_registry_interface, + &wl_surface_interface, + &wl_region_interface, + &wl_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_shm_pool_interface, + NULL, + NULL, + &wl_data_source_interface, + &wl_surface_interface, + &wl_surface_interface, + NULL, + &wl_data_source_interface, + NULL, + &wl_data_offer_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + &wl_data_offer_interface, + &wl_data_offer_interface, + &wl_data_source_interface, + &wl_data_device_interface, + &wl_seat_interface, + &wl_shell_surface_interface, + &wl_surface_interface, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_output_interface, + &wl_buffer_interface, + NULL, + NULL, + &wl_callback_interface, + &wl_region_interface, + &wl_region_interface, + &wl_output_interface, + &wl_output_interface, + &wl_pointer_interface, + &wl_keyboard_interface, + &wl_touch_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_surface_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_subsurface_interface, + &wl_surface_interface, + &wl_surface_interface, + &wl_surface_interface, + &wl_surface_interface, +}; + +static const struct wl_message wl_display_requests[] = { + { "sync", "n", types + 8 }, + { "get_registry", "n", types + 9 }, +}; + +static const struct wl_message wl_display_events[] = { + { "error", "ous", types + 0 }, + { "delete_id", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_display_interface = { + "wl_display", 1, + 2, wl_display_requests, + 2, wl_display_events, +}; + +static const struct wl_message wl_registry_requests[] = { + { "bind", "usun", types + 0 }, +}; + +static const struct wl_message wl_registry_events[] = { + { "global", "usu", types + 0 }, + { "global_remove", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_registry_interface = { + "wl_registry", 1, + 1, wl_registry_requests, + 2, wl_registry_events, +}; + +static const struct wl_message wl_callback_events[] = { + { "done", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_callback_interface = { + "wl_callback", 1, + 0, NULL, + 1, wl_callback_events, +}; + +static const struct wl_message wl_compositor_requests[] = { + { "create_surface", "n", types + 10 }, + { "create_region", "n", types + 11 }, +}; + +WL_EXPORT const struct wl_interface wl_compositor_interface = { + "wl_compositor", 4, + 2, wl_compositor_requests, + 0, NULL, +}; + +static const struct wl_message wl_shm_pool_requests[] = { + { "create_buffer", "niiiiu", types + 12 }, + { "destroy", "", types + 0 }, + { "resize", "i", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_shm_pool_interface = { + "wl_shm_pool", 1, + 3, wl_shm_pool_requests, + 0, NULL, +}; + +static const struct wl_message wl_shm_requests[] = { + { "create_pool", "nhi", types + 18 }, +}; + +static const struct wl_message wl_shm_events[] = { + { "format", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_shm_interface = { + "wl_shm", 1, + 1, wl_shm_requests, + 1, wl_shm_events, +}; + +static const struct wl_message wl_buffer_requests[] = { + { "destroy", "", types + 0 }, +}; + +static const struct wl_message wl_buffer_events[] = { + { "release", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_buffer_interface = { + "wl_buffer", 1, + 1, wl_buffer_requests, + 1, wl_buffer_events, +}; + +static const struct wl_message wl_data_offer_requests[] = { + { "accept", "u?s", types + 0 }, + { "receive", "sh", types + 0 }, + { "destroy", "", types + 0 }, + { "finish", "3", types + 0 }, + { "set_actions", "3uu", types + 0 }, +}; + +static const struct wl_message wl_data_offer_events[] = { + { "offer", "s", types + 0 }, + { "source_actions", "3u", types + 0 }, + { "action", "3u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_data_offer_interface = { + "wl_data_offer", 3, + 5, wl_data_offer_requests, + 3, wl_data_offer_events, +}; + +static const struct wl_message wl_data_source_requests[] = { + { "offer", "s", types + 0 }, + { "destroy", "", types + 0 }, + { "set_actions", "3u", types + 0 }, +}; + +static const struct wl_message wl_data_source_events[] = { + { "target", "?s", types + 0 }, + { "send", "sh", types + 0 }, + { "cancelled", "", types + 0 }, + { "dnd_drop_performed", "3", types + 0 }, + { "dnd_finished", "3", types + 0 }, + { "action", "3u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_data_source_interface = { + "wl_data_source", 3, + 3, wl_data_source_requests, + 6, wl_data_source_events, +}; + +static const struct wl_message wl_data_device_requests[] = { + { "start_drag", "?oo?ou", types + 21 }, + { "set_selection", "?ou", types + 25 }, + { "release", "2", types + 0 }, +}; + +static const struct wl_message wl_data_device_events[] = { + { "data_offer", "n", types + 27 }, + { "enter", "uoff?o", types + 28 }, + { "leave", "", types + 0 }, + { "motion", "uff", types + 0 }, + { "drop", "", types + 0 }, + { "selection", "?o", types + 33 }, +}; + +WL_EXPORT const struct wl_interface wl_data_device_interface = { + "wl_data_device", 3, + 3, wl_data_device_requests, + 6, wl_data_device_events, +}; + +static const struct wl_message wl_data_device_manager_requests[] = { + { "create_data_source", "n", types + 34 }, + { "get_data_device", "no", types + 35 }, +}; + +WL_EXPORT const struct wl_interface wl_data_device_manager_interface = { + "wl_data_device_manager", 3, + 2, wl_data_device_manager_requests, + 0, NULL, +}; + +static const struct wl_message wl_shell_requests[] = { + { "get_shell_surface", "no", types + 37 }, +}; + +WL_EXPORT const struct wl_interface wl_shell_interface = { + "wl_shell", 1, + 1, wl_shell_requests, + 0, NULL, +}; + +static const struct wl_message wl_shell_surface_requests[] = { + { "pong", "u", types + 0 }, + { "move", "ou", types + 39 }, + { "resize", "ouu", types + 41 }, + { "set_toplevel", "", types + 0 }, + { "set_transient", "oiiu", types + 44 }, + { "set_fullscreen", "uu?o", types + 48 }, + { "set_popup", "ouoiiu", types + 51 }, + { "set_maximized", "?o", types + 57 }, + { "set_title", "s", types + 0 }, + { "set_class", "s", types + 0 }, +}; + +static const struct wl_message wl_shell_surface_events[] = { + { "ping", "u", types + 0 }, + { "configure", "uii", types + 0 }, + { "popup_done", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_shell_surface_interface = { + "wl_shell_surface", 1, + 10, wl_shell_surface_requests, + 3, wl_shell_surface_events, +}; + +static const struct wl_message wl_surface_requests[] = { + { "destroy", "", types + 0 }, + { "attach", "?oii", types + 58 }, + { "damage", "iiii", types + 0 }, + { "frame", "n", types + 61 }, + { "set_opaque_region", "?o", types + 62 }, + { "set_input_region", "?o", types + 63 }, + { "commit", "", types + 0 }, + { "set_buffer_transform", "2i", types + 0 }, + { "set_buffer_scale", "3i", types + 0 }, + { "damage_buffer", "4iiii", types + 0 }, +}; + +static const struct wl_message wl_surface_events[] = { + { "enter", "o", types + 64 }, + { "leave", "o", types + 65 }, +}; + +WL_EXPORT const struct wl_interface wl_surface_interface = { + "wl_surface", 4, + 10, wl_surface_requests, + 2, wl_surface_events, +}; + +static const struct wl_message wl_seat_requests[] = { + { "get_pointer", "n", types + 66 }, + { "get_keyboard", "n", types + 67 }, + { "get_touch", "n", types + 68 }, + { "release", "5", types + 0 }, +}; + +static const struct wl_message wl_seat_events[] = { + { "capabilities", "u", types + 0 }, + { "name", "2s", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_seat_interface = { + "wl_seat", 5, + 4, wl_seat_requests, + 2, wl_seat_events, +}; + +static const struct wl_message wl_pointer_requests[] = { + { "set_cursor", "u?oii", types + 69 }, + { "release", "3", types + 0 }, +}; + +static const struct wl_message wl_pointer_events[] = { + { "enter", "uoff", types + 73 }, + { "leave", "uo", types + 77 }, + { "motion", "uff", types + 0 }, + { "button", "uuuu", types + 0 }, + { "axis", "uuf", types + 0 }, + { "frame", "5", types + 0 }, + { "axis_source", "5u", types + 0 }, + { "axis_stop", "5uu", types + 0 }, + { "axis_discrete", "5ui", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_pointer_interface = { + "wl_pointer", 5, + 2, wl_pointer_requests, + 9, wl_pointer_events, +}; + +static const struct wl_message wl_keyboard_requests[] = { + { "release", "3", types + 0 }, +}; + +static const struct wl_message wl_keyboard_events[] = { + { "keymap", "uhu", types + 0 }, + { "enter", "uoa", types + 79 }, + { "leave", "uo", types + 82 }, + { "key", "uuuu", types + 0 }, + { "modifiers", "uuuuu", types + 0 }, + { "repeat_info", "4ii", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_keyboard_interface = { + "wl_keyboard", 5, + 1, wl_keyboard_requests, + 6, wl_keyboard_events, +}; + +static const struct wl_message wl_touch_requests[] = { + { "release", "3", types + 0 }, +}; + +static const struct wl_message wl_touch_events[] = { + { "down", "uuoiff", types + 84 }, + { "up", "uui", types + 0 }, + { "motion", "uiff", types + 0 }, + { "frame", "", types + 0 }, + { "cancel", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_touch_interface = { + "wl_touch", 5, + 1, wl_touch_requests, + 5, wl_touch_events, +}; + +static const struct wl_message wl_output_requests[] = { + { "release", "3", types + 0 }, +}; + +static const struct wl_message wl_output_events[] = { + { "geometry", "iiiiissi", types + 0 }, + { "mode", "uiii", types + 0 }, + { "done", "2", types + 0 }, + { "scale", "2i", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_output_interface = { + "wl_output", 3, + 1, wl_output_requests, + 4, wl_output_events, +}; + +static const struct wl_message wl_region_requests[] = { + { "destroy", "", types + 0 }, + { "add", "iiii", types + 0 }, + { "subtract", "iiii", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_region_interface = { + "wl_region", 1, + 3, wl_region_requests, + 0, NULL, +}; + +static const struct wl_message wl_subcompositor_requests[] = { + { "destroy", "", types + 0 }, + { "get_subsurface", "noo", types + 90 }, +}; + +WL_EXPORT const struct wl_interface wl_subcompositor_interface = { + "wl_subcompositor", 1, + 2, wl_subcompositor_requests, + 0, NULL, +}; + +static const struct wl_message wl_subsurface_requests[] = { + { "destroy", "", types + 0 }, + { "set_position", "ii", types + 0 }, + { "place_above", "o", types + 93 }, + { "place_below", "o", types + 94 }, + { "set_sync", "", types + 0 }, + { "set_desync", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_subsurface_interface = { + "wl_subsurface", 1, + 6, wl_subsurface_requests, + 0, NULL, +}; + diff --git a/tests/data/example-server.h b/tests/data/example-server.h new file mode 100644 index 00000000..22550f6c --- /dev/null +++ b/tests/data/example-server.h @@ -0,0 +1,4285 @@ +/* SCANNER TEST */ + +#ifndef WAYLAND_SERVER_PROTOCOL_H +#define WAYLAND_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_wayland The wayland protocol + * @section page_ifaces_wayland Interfaces + * - @subpage page_iface_wl_display - core global object + * - @subpage page_iface_wl_registry - global registry object + * - @subpage page_iface_wl_callback - callback object + * - @subpage page_iface_wl_compositor - the compositor singleton + * - @subpage page_iface_wl_shm_pool - a shared memory pool + * - @subpage page_iface_wl_shm - shared memory support + * - @subpage page_iface_wl_buffer - content for a wl_surface + * - @subpage page_iface_wl_data_offer - offer to transfer data + * - @subpage page_iface_wl_data_source - offer to transfer data + * - @subpage page_iface_wl_data_device - data transfer device + * - @subpage page_iface_wl_data_device_manager - data transfer interface + * - @subpage page_iface_wl_shell - create desktop-style surfaces + * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface + * - @subpage page_iface_wl_surface - an onscreen surface + * - @subpage page_iface_wl_seat - group of input devices + * - @subpage page_iface_wl_pointer - pointer input device + * - @subpage page_iface_wl_keyboard - keyboard input device + * - @subpage page_iface_wl_touch - touchscreen input device + * - @subpage page_iface_wl_output - compositor output region + * - @subpage page_iface_wl_region - region interface + * - @subpage page_iface_wl_subcompositor - sub-surface compositing + * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface + * @section page_copyright_wayland Copyright + *
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct wl_buffer; +struct wl_callback; +struct wl_compositor; +struct wl_data_device; +struct wl_data_device_manager; +struct wl_data_offer; +struct wl_data_source; +struct wl_display; +struct wl_keyboard; +struct wl_output; +struct wl_pointer; +struct wl_region; +struct wl_registry; +struct wl_seat; +struct wl_shell; +struct wl_shell_surface; +struct wl_shm; +struct wl_shm_pool; +struct wl_subcompositor; +struct wl_subsurface; +struct wl_surface; +struct wl_touch; + +/** + * @page page_iface_wl_display wl_display + * @section page_iface_wl_display_desc Description + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + * @section page_iface_wl_display_api API + * See @ref iface_wl_display. + */ +/** + * @defgroup iface_wl_display The wl_display interface + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + */ +extern const struct wl_interface wl_display_interface; +/** + * @page page_iface_wl_registry wl_registry + * @section page_iface_wl_registry_desc Description + * + * The global registry object. The server has a number of global + * objects that are available to all clients. These objects + * typically represent an actual object in the server (for example, + * an input device) or they are singleton objects that provide + * extension functionality. + * + * When a client creates a registry object, the registry object + * will emit a global event for each global currently in the + * registry. Globals come and go as a result of device or + * monitor hotplugs, reconfiguration or other events, and the + * registry will send out global and global_remove events to + * keep the client up to date with the changes. To mark the end + * of the initial burst of events, the client can use the + * wl_display.sync request immediately after calling + * wl_display.get_registry. + * + * A client can bind to a global object by using the bind + * request. This creates a client-side handle that lets the object + * emit events to the client and lets the client invoke requests on + * the object. + * @section page_iface_wl_registry_api API + * See @ref iface_wl_registry. + */ +/** + * @defgroup iface_wl_registry The wl_registry interface + * + * The global registry object. The server has a number of global + * objects that are available to all clients. These objects + * typically represent an actual object in the server (for example, + * an input device) or they are singleton objects that provide + * extension functionality. + * + * When a client creates a registry object, the registry object + * will emit a global event for each global currently in the + * registry. Globals come and go as a result of device or + * monitor hotplugs, reconfiguration or other events, and the + * registry will send out global and global_remove events to + * keep the client up to date with the changes. To mark the end + * of the initial burst of events, the client can use the + * wl_display.sync request immediately after calling + * wl_display.get_registry. + * + * A client can bind to a global object by using the bind + * request. This creates a client-side handle that lets the object + * emit events to the client and lets the client invoke requests on + * the object. + */ +extern const struct wl_interface wl_registry_interface; +/** + * @page page_iface_wl_callback wl_callback + * @section page_iface_wl_callback_desc Description + * + * Clients can handle the 'done' event to get notified when + * the related request is done. + * @section page_iface_wl_callback_api API + * See @ref iface_wl_callback. + */ +/** + * @defgroup iface_wl_callback The wl_callback interface + * + * Clients can handle the 'done' event to get notified when + * the related request is done. + */ +extern const struct wl_interface wl_callback_interface; +/** + * @page page_iface_wl_compositor wl_compositor + * @section page_iface_wl_compositor_desc Description + * + * A compositor. This object is a singleton global. The + * compositor is in charge of combining the contents of multiple + * surfaces into one displayable output. + * @section page_iface_wl_compositor_api API + * See @ref iface_wl_compositor. + */ +/** + * @defgroup iface_wl_compositor The wl_compositor interface + * + * A compositor. This object is a singleton global. The + * compositor is in charge of combining the contents of multiple + * surfaces into one displayable output. + */ +extern const struct wl_interface wl_compositor_interface; +/** + * @page page_iface_wl_shm_pool wl_shm_pool + * @section page_iface_wl_shm_pool_desc Description + * + * The wl_shm_pool object encapsulates a piece of memory shared + * between the compositor and client. Through the wl_shm_pool + * object, the client can allocate shared memory wl_buffer objects. + * All objects created through the same pool share the same + * underlying mapped memory. Reusing the mapped memory avoids the + * setup/teardown overhead and is useful when interactively resizing + * a surface or for many small buffers. + * @section page_iface_wl_shm_pool_api API + * See @ref iface_wl_shm_pool. + */ +/** + * @defgroup iface_wl_shm_pool The wl_shm_pool interface + * + * The wl_shm_pool object encapsulates a piece of memory shared + * between the compositor and client. Through the wl_shm_pool + * object, the client can allocate shared memory wl_buffer objects. + * All objects created through the same pool share the same + * underlying mapped memory. Reusing the mapped memory avoids the + * setup/teardown overhead and is useful when interactively resizing + * a surface or for many small buffers. + */ +extern const struct wl_interface wl_shm_pool_interface; +/** + * @page page_iface_wl_shm wl_shm + * @section page_iface_wl_shm_desc Description + * + * A global singleton object that provides support for shared + * memory. + * + * Clients can create wl_shm_pool objects using the create_pool + * request. + * + * At connection setup time, the wl_shm object emits one or more + * format events to inform clients about the valid pixel formats + * that can be used for buffers. + * @section page_iface_wl_shm_api API + * See @ref iface_wl_shm. + */ +/** + * @defgroup iface_wl_shm The wl_shm interface + * + * A global singleton object that provides support for shared + * memory. + * + * Clients can create wl_shm_pool objects using the create_pool + * request. + * + * At connection setup time, the wl_shm object emits one or more + * format events to inform clients about the valid pixel formats + * that can be used for buffers. + */ +extern const struct wl_interface wl_shm_interface; +/** + * @page page_iface_wl_buffer wl_buffer + * @section page_iface_wl_buffer_desc Description + * + * A buffer provides the content for a wl_surface. Buffers are + * created through factory interfaces such as wl_drm, wl_shm or + * similar. It has a width and a height and can be attached to a + * wl_surface, but the mechanism by which a client provides and + * updates the contents is defined by the buffer factory interface. + * @section page_iface_wl_buffer_api API + * See @ref iface_wl_buffer. + */ +/** + * @defgroup iface_wl_buffer The wl_buffer interface + * + * A buffer provides the content for a wl_surface. Buffers are + * created through factory interfaces such as wl_drm, wl_shm or + * similar. It has a width and a height and can be attached to a + * wl_surface, but the mechanism by which a client provides and + * updates the contents is defined by the buffer factory interface. + */ +extern const struct wl_interface wl_buffer_interface; +/** + * @page page_iface_wl_data_offer wl_data_offer + * @section page_iface_wl_data_offer_desc Description + * + * A wl_data_offer represents a piece of data offered for transfer + * by another client (the source client). It is used by the + * copy-and-paste and drag-and-drop mechanisms. The offer + * describes the different mime types that the data can be + * converted to and provides the mechanism for transferring the + * data directly from the source client. + * @section page_iface_wl_data_offer_api API + * See @ref iface_wl_data_offer. + */ +/** + * @defgroup iface_wl_data_offer The wl_data_offer interface + * + * A wl_data_offer represents a piece of data offered for transfer + * by another client (the source client). It is used by the + * copy-and-paste and drag-and-drop mechanisms. The offer + * describes the different mime types that the data can be + * converted to and provides the mechanism for transferring the + * data directly from the source client. + */ +extern const struct wl_interface wl_data_offer_interface; +/** + * @page page_iface_wl_data_source wl_data_source + * @section page_iface_wl_data_source_desc Description + * + * The wl_data_source object is the source side of a wl_data_offer. + * It is created by the source client in a data transfer and + * provides a way to describe the offered data and a way to respond + * to requests to transfer the data. + * @section page_iface_wl_data_source_api API + * See @ref iface_wl_data_source. + */ +/** + * @defgroup iface_wl_data_source The wl_data_source interface + * + * The wl_data_source object is the source side of a wl_data_offer. + * It is created by the source client in a data transfer and + * provides a way to describe the offered data and a way to respond + * to requests to transfer the data. + */ +extern const struct wl_interface wl_data_source_interface; +/** + * @page page_iface_wl_data_device wl_data_device + * @section page_iface_wl_data_device_desc Description + * + * There is one wl_data_device per seat which can be obtained + * from the global wl_data_device_manager singleton. + * + * A wl_data_device provides access to inter-client data transfer + * mechanisms such as copy-and-paste and drag-and-drop. + * @section page_iface_wl_data_device_api API + * See @ref iface_wl_data_device. + */ +/** + * @defgroup iface_wl_data_device The wl_data_device interface + * + * There is one wl_data_device per seat which can be obtained + * from the global wl_data_device_manager singleton. + * + * A wl_data_device provides access to inter-client data transfer + * mechanisms such as copy-and-paste and drag-and-drop. + */ +extern const struct wl_interface wl_data_device_interface; +/** + * @page page_iface_wl_data_device_manager wl_data_device_manager + * @section page_iface_wl_data_device_manager_desc Description + * + * The wl_data_device_manager is a singleton global object that + * provides access to inter-client data transfer mechanisms such as + * copy-and-paste and drag-and-drop. These mechanisms are tied to + * a wl_seat and this interface lets a client get a wl_data_device + * corresponding to a wl_seat. + * + * Depending on the version bound, the objects created from the bound + * wl_data_device_manager object will have different requirements for + * functioning properly. See wl_data_source.set_actions, + * wl_data_offer.accept and wl_data_offer.finish for details. + * @section page_iface_wl_data_device_manager_api API + * See @ref iface_wl_data_device_manager. + */ +/** + * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface + * + * The wl_data_device_manager is a singleton global object that + * provides access to inter-client data transfer mechanisms such as + * copy-and-paste and drag-and-drop. These mechanisms are tied to + * a wl_seat and this interface lets a client get a wl_data_device + * corresponding to a wl_seat. + * + * Depending on the version bound, the objects created from the bound + * wl_data_device_manager object will have different requirements for + * functioning properly. See wl_data_source.set_actions, + * wl_data_offer.accept and wl_data_offer.finish for details. + */ +extern const struct wl_interface wl_data_device_manager_interface; +/** + * @page page_iface_wl_shell wl_shell + * @section page_iface_wl_shell_desc Description + * + * This interface is implemented by servers that provide + * desktop-style user interfaces. + * + * It allows clients to associate a wl_shell_surface with + * a basic surface. + * @section page_iface_wl_shell_api API + * See @ref iface_wl_shell. + */ +/** + * @defgroup iface_wl_shell The wl_shell interface + * + * This interface is implemented by servers that provide + * desktop-style user interfaces. + * + * It allows clients to associate a wl_shell_surface with + * a basic surface. + */ +extern const struct wl_interface wl_shell_interface; +/** + * @page page_iface_wl_shell_surface wl_shell_surface + * @section page_iface_wl_shell_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like toplevel, fullscreen + * or popup windows, move, resize or maximize them, associate + * metadata like title and class, etc. + * + * On the server side the object is automatically destroyed when + * the related wl_surface is destroyed. On the client side, + * wl_shell_surface_destroy() must be called before destroying + * the wl_surface object. + * @section page_iface_wl_shell_surface_api API + * See @ref iface_wl_shell_surface. + */ +/** + * @defgroup iface_wl_shell_surface The wl_shell_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like toplevel, fullscreen + * or popup windows, move, resize or maximize them, associate + * metadata like title and class, etc. + * + * On the server side the object is automatically destroyed when + * the related wl_surface is destroyed. On the client side, + * wl_shell_surface_destroy() must be called before destroying + * the wl_surface object. + */ +extern const struct wl_interface wl_shell_surface_interface; +/** + * @page page_iface_wl_surface wl_surface + * @section page_iface_wl_surface_desc Description + * + * A surface is a rectangular area that is displayed on the screen. + * It has a location, size and pixel contents. + * + * The size of a surface (and relative positions on it) is described + * in surface-local coordinates, which may differ from the buffer + * coordinates of the pixel content, in case a buffer_transform + * or a buffer_scale is used. + * + * A surface without a "role" is fairly useless: a compositor does + * not know where, when or how to present it. The role is the + * purpose of a wl_surface. Examples of roles are a cursor for a + * pointer (as set by wl_pointer.set_cursor), a drag icon + * (wl_data_device.start_drag), a sub-surface + * (wl_subcompositor.get_subsurface), and a window as defined by a + * shell protocol (e.g. wl_shell.get_shell_surface). + * + * A surface can have only one role at a time. Initially a + * wl_surface does not have a role. Once a wl_surface is given a + * role, it is set permanently for the whole lifetime of the + * wl_surface object. Giving the current role again is allowed, + * unless explicitly forbidden by the relevant interface + * specification. + * + * Surface roles are given by requests in other interfaces such as + * wl_pointer.set_cursor. The request should explicitly mention + * that this request gives a role to a wl_surface. Often, this + * request also creates a new protocol object that represents the + * role and adds additional functionality to wl_surface. When a + * client wants to destroy a wl_surface, they must destroy this 'role + * object' before the wl_surface. + * + * Destroying the role object does not remove the role from the + * wl_surface, but it may stop the wl_surface from "playing the role". + * For instance, if a wl_subsurface object is destroyed, the wl_surface + * it was created for will be unmapped and forget its position and + * z-order. It is allowed to create a wl_subsurface for the same + * wl_surface again, but it is not allowed to use the wl_surface as + * a cursor (cursor is a different role than sub-surface, and role + * switching is not allowed). + * @section page_iface_wl_surface_api API + * See @ref iface_wl_surface. + */ +/** + * @defgroup iface_wl_surface The wl_surface interface + * + * A surface is a rectangular area that is displayed on the screen. + * It has a location, size and pixel contents. + * + * The size of a surface (and relative positions on it) is described + * in surface-local coordinates, which may differ from the buffer + * coordinates of the pixel content, in case a buffer_transform + * or a buffer_scale is used. + * + * A surface without a "role" is fairly useless: a compositor does + * not know where, when or how to present it. The role is the + * purpose of a wl_surface. Examples of roles are a cursor for a + * pointer (as set by wl_pointer.set_cursor), a drag icon + * (wl_data_device.start_drag), a sub-surface + * (wl_subcompositor.get_subsurface), and a window as defined by a + * shell protocol (e.g. wl_shell.get_shell_surface). + * + * A surface can have only one role at a time. Initially a + * wl_surface does not have a role. Once a wl_surface is given a + * role, it is set permanently for the whole lifetime of the + * wl_surface object. Giving the current role again is allowed, + * unless explicitly forbidden by the relevant interface + * specification. + * + * Surface roles are given by requests in other interfaces such as + * wl_pointer.set_cursor. The request should explicitly mention + * that this request gives a role to a wl_surface. Often, this + * request also creates a new protocol object that represents the + * role and adds additional functionality to wl_surface. When a + * client wants to destroy a wl_surface, they must destroy this 'role + * object' before the wl_surface. + * + * Destroying the role object does not remove the role from the + * wl_surface, but it may stop the wl_surface from "playing the role". + * For instance, if a wl_subsurface object is destroyed, the wl_surface + * it was created for will be unmapped and forget its position and + * z-order. It is allowed to create a wl_subsurface for the same + * wl_surface again, but it is not allowed to use the wl_surface as + * a cursor (cursor is a different role than sub-surface, and role + * switching is not allowed). + */ +extern const struct wl_interface wl_surface_interface; +/** + * @page page_iface_wl_seat wl_seat + * @section page_iface_wl_seat_desc Description + * + * A seat is a group of keyboards, pointer and touch devices. This + * object is published as a global during start up, or when such a + * device is hot plugged. A seat typically has a pointer and + * maintains a keyboard focus and a pointer focus. + * @section page_iface_wl_seat_api API + * See @ref iface_wl_seat. + */ +/** + * @defgroup iface_wl_seat The wl_seat interface + * + * A seat is a group of keyboards, pointer and touch devices. This + * object is published as a global during start up, or when such a + * device is hot plugged. A seat typically has a pointer and + * maintains a keyboard focus and a pointer focus. + */ +extern const struct wl_interface wl_seat_interface; +/** + * @page page_iface_wl_pointer wl_pointer + * @section page_iface_wl_pointer_desc Description + * + * The wl_pointer interface represents one or more input devices, + * such as mice, which control the pointer location and pointer_focus + * of a seat. + * + * The wl_pointer interface generates motion, enter and leave + * events for the surfaces that the pointer is located over, + * and button and axis events for button presses, button releases + * and scrolling. + * @section page_iface_wl_pointer_api API + * See @ref iface_wl_pointer. + */ +/** + * @defgroup iface_wl_pointer The wl_pointer interface + * + * The wl_pointer interface represents one or more input devices, + * such as mice, which control the pointer location and pointer_focus + * of a seat. + * + * The wl_pointer interface generates motion, enter and leave + * events for the surfaces that the pointer is located over, + * and button and axis events for button presses, button releases + * and scrolling. + */ +extern const struct wl_interface wl_pointer_interface; +/** + * @page page_iface_wl_keyboard wl_keyboard + * @section page_iface_wl_keyboard_desc Description + * + * The wl_keyboard interface represents one or more keyboards + * associated with a seat. + * @section page_iface_wl_keyboard_api API + * See @ref iface_wl_keyboard. + */ +/** + * @defgroup iface_wl_keyboard The wl_keyboard interface + * + * The wl_keyboard interface represents one or more keyboards + * associated with a seat. + */ +extern const struct wl_interface wl_keyboard_interface; +/** + * @page page_iface_wl_touch wl_touch + * @section page_iface_wl_touch_desc Description + * + * The wl_touch interface represents a touchscreen + * associated with a seat. + * + * Touch interactions can consist of one or more contacts. + * For each contact, a series of events is generated, starting + * with a down event, followed by zero or more motion events, + * and ending with an up event. Events relating to the same + * contact point can be identified by the ID of the sequence. + * @section page_iface_wl_touch_api API + * See @ref iface_wl_touch. + */ +/** + * @defgroup iface_wl_touch The wl_touch interface + * + * The wl_touch interface represents a touchscreen + * associated with a seat. + * + * Touch interactions can consist of one or more contacts. + * For each contact, a series of events is generated, starting + * with a down event, followed by zero or more motion events, + * and ending with an up event. Events relating to the same + * contact point can be identified by the ID of the sequence. + */ +extern const struct wl_interface wl_touch_interface; +/** + * @page page_iface_wl_output wl_output + * @section page_iface_wl_output_desc Description + * + * An output describes part of the compositor geometry. The + * compositor works in the 'compositor coordinate system' and an + * output corresponds to a rectangular area in that space that is + * actually visible. This typically corresponds to a monitor that + * displays part of the compositor space. This object is published + * as global during start up, or when a monitor is hotplugged. + * @section page_iface_wl_output_api API + * See @ref iface_wl_output. + */ +/** + * @defgroup iface_wl_output The wl_output interface + * + * An output describes part of the compositor geometry. The + * compositor works in the 'compositor coordinate system' and an + * output corresponds to a rectangular area in that space that is + * actually visible. This typically corresponds to a monitor that + * displays part of the compositor space. This object is published + * as global during start up, or when a monitor is hotplugged. + */ +extern const struct wl_interface wl_output_interface; +/** + * @page page_iface_wl_region wl_region + * @section page_iface_wl_region_desc Description + * + * A region object describes an area. + * + * Region objects are used to describe the opaque and input + * regions of a surface. + * @section page_iface_wl_region_api API + * See @ref iface_wl_region. + */ +/** + * @defgroup iface_wl_region The wl_region interface + * + * A region object describes an area. + * + * Region objects are used to describe the opaque and input + * regions of a surface. + */ +extern const struct wl_interface wl_region_interface; +/** + * @page page_iface_wl_subcompositor wl_subcompositor + * @section page_iface_wl_subcompositor_desc Description + * + * The global interface exposing sub-surface compositing capabilities. + * A wl_surface, that has sub-surfaces associated, is called the + * parent surface. Sub-surfaces can be arbitrarily nested and create + * a tree of sub-surfaces. + * + * The root surface in a tree of sub-surfaces is the main + * surface. The main surface cannot be a sub-surface, because + * sub-surfaces must always have a parent. + * + * A main surface with its sub-surfaces forms a (compound) window. + * For window management purposes, this set of wl_surface objects is + * to be considered as a single window, and it should also behave as + * such. + * + * The aim of sub-surfaces is to offload some of the compositing work + * within a window from clients to the compositor. A prime example is + * a video player with decorations and video in separate wl_surface + * objects. This should allow the compositor to pass YUV video buffer + * processing to dedicated overlay hardware when possible. + * @section page_iface_wl_subcompositor_api API + * See @ref iface_wl_subcompositor. + */ +/** + * @defgroup iface_wl_subcompositor The wl_subcompositor interface + * + * The global interface exposing sub-surface compositing capabilities. + * A wl_surface, that has sub-surfaces associated, is called the + * parent surface. Sub-surfaces can be arbitrarily nested and create + * a tree of sub-surfaces. + * + * The root surface in a tree of sub-surfaces is the main + * surface. The main surface cannot be a sub-surface, because + * sub-surfaces must always have a parent. + * + * A main surface with its sub-surfaces forms a (compound) window. + * For window management purposes, this set of wl_surface objects is + * to be considered as a single window, and it should also behave as + * such. + * + * The aim of sub-surfaces is to offload some of the compositing work + * within a window from clients to the compositor. A prime example is + * a video player with decorations and video in separate wl_surface + * objects. This should allow the compositor to pass YUV video buffer + * processing to dedicated overlay hardware when possible. + */ +extern const struct wl_interface wl_subcompositor_interface; +/** + * @page page_iface_wl_subsurface wl_subsurface + * @section page_iface_wl_subsurface_desc Description + * + * An additional interface to a wl_surface object, which has been + * made a sub-surface. A sub-surface has one parent surface. A + * sub-surface's size and position are not limited to that of the parent. + * Particularly, a sub-surface is not automatically clipped to its + * parent's area. + * + * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped. The order of which one happens + * first is irrelevant. A sub-surface is hidden if the parent becomes + * hidden, or if a NULL wl_buffer is applied. These rules apply + * recursively through the tree of surfaces. + * + * The behaviour of a wl_surface.commit request on a sub-surface + * depends on the sub-surface's mode. The possible modes are + * synchronized and desynchronized, see methods + * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + * mode caches the wl_surface state to be applied when the parent's + * state gets applied, and desynchronized mode applies the pending + * wl_surface state directly. A sub-surface is initially in the + * synchronized mode. + * + * Sub-surfaces have also other kind of state, which is managed by + * wl_subsurface requests, as opposed to wl_surface requests. This + * state includes the sub-surface position relative to the parent + * surface (wl_subsurface.set_position), and the stacking order of + * the parent and its sub-surfaces (wl_subsurface.place_above and + * .place_below). This state is applied when the parent surface's + * wl_surface state is applied, regardless of the sub-surface's mode. + * As the exception, set_sync and set_desync are effective immediately. + * + * The main surface can be thought to be always in desynchronized mode, + * since it does not have a parent in the sub-surfaces sense. + * + * Even if a sub-surface is in desynchronized mode, it will behave as + * in synchronized mode, if its parent surface behaves as in + * synchronized mode. This rule is applied recursively throughout the + * tree of surfaces. This means, that one can set a sub-surface into + * synchronized mode, and then assume that all its child and grand-child + * sub-surfaces are synchronized, too, without explicitly setting them. + * + * If the wl_surface associated with the wl_subsurface is destroyed, the + * wl_subsurface object becomes inert. Note, that destroying either object + * takes effect immediately. If you need to synchronize the removal + * of a sub-surface to the parent surface update, unmap the sub-surface + * first by attaching a NULL wl_buffer, update parent, and then destroy + * the sub-surface. + * + * If the parent wl_surface object is destroyed, the sub-surface is + * unmapped. + * @section page_iface_wl_subsurface_api API + * See @ref iface_wl_subsurface. + */ +/** + * @defgroup iface_wl_subsurface The wl_subsurface interface + * + * An additional interface to a wl_surface object, which has been + * made a sub-surface. A sub-surface has one parent surface. A + * sub-surface's size and position are not limited to that of the parent. + * Particularly, a sub-surface is not automatically clipped to its + * parent's area. + * + * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped. The order of which one happens + * first is irrelevant. A sub-surface is hidden if the parent becomes + * hidden, or if a NULL wl_buffer is applied. These rules apply + * recursively through the tree of surfaces. + * + * The behaviour of a wl_surface.commit request on a sub-surface + * depends on the sub-surface's mode. The possible modes are + * synchronized and desynchronized, see methods + * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + * mode caches the wl_surface state to be applied when the parent's + * state gets applied, and desynchronized mode applies the pending + * wl_surface state directly. A sub-surface is initially in the + * synchronized mode. + * + * Sub-surfaces have also other kind of state, which is managed by + * wl_subsurface requests, as opposed to wl_surface requests. This + * state includes the sub-surface position relative to the parent + * surface (wl_subsurface.set_position), and the stacking order of + * the parent and its sub-surfaces (wl_subsurface.place_above and + * .place_below). This state is applied when the parent surface's + * wl_surface state is applied, regardless of the sub-surface's mode. + * As the exception, set_sync and set_desync are effective immediately. + * + * The main surface can be thought to be always in desynchronized mode, + * since it does not have a parent in the sub-surfaces sense. + * + * Even if a sub-surface is in desynchronized mode, it will behave as + * in synchronized mode, if its parent surface behaves as in + * synchronized mode. This rule is applied recursively throughout the + * tree of surfaces. This means, that one can set a sub-surface into + * synchronized mode, and then assume that all its child and grand-child + * sub-surfaces are synchronized, too, without explicitly setting them. + * + * If the wl_surface associated with the wl_subsurface is destroyed, the + * wl_subsurface object becomes inert. Note, that destroying either object + * takes effect immediately. If you need to synchronize the removal + * of a sub-surface to the parent surface update, unmap the sub-surface + * first by attaching a NULL wl_buffer, update parent, and then destroy + * the sub-surface. + * + * If the parent wl_surface object is destroyed, the sub-surface is + * unmapped. + */ +extern const struct wl_interface wl_subsurface_interface; + +#ifndef WL_DISPLAY_ERROR_ENUM +#define WL_DISPLAY_ERROR_ENUM +/** + * @ingroup iface_wl_display + * global error values + * + * These errors are global and can be emitted in response to any + * server request. + */ +enum wl_display_error { + /** + * server couldn't find object + */ + WL_DISPLAY_ERROR_INVALID_OBJECT = 0, + /** + * method doesn't exist on the specified interface + */ + WL_DISPLAY_ERROR_INVALID_METHOD = 1, + /** + * server is out of memory + */ + WL_DISPLAY_ERROR_NO_MEMORY = 2, +}; +#endif /* WL_DISPLAY_ERROR_ENUM */ + +/** + * @ingroup iface_wl_display + * @struct wl_display_interface + */ +struct wl_display_interface { + /** + * asynchronous roundtrip + * + * The sync request asks the server to emit the 'done' event on + * the returned wl_callback object. Since requests are handled + * in-order and events are delivered in-order, this can be used as + * a barrier to ensure all previous requests and the resulting + * events have been handled. + * + * The object returned by this request will be destroyed by the + * compositor after the callback is fired and as such the client + * must not attempt to use it after that point. + * + * The callback_data passed in the callback is the event serial. + * @param callback callback object for the sync request + */ + void (*sync)(struct wl_client *client, + struct wl_resource *resource, + uint32_t callback); + /** + * get global registry object + * + * This request creates a registry object that allows the client + * to list and bind the global objects available from the + * compositor. + * @param registry global registry object + */ + void (*get_registry)(struct wl_client *client, + struct wl_resource *resource, + uint32_t registry); +}; + +#define WL_DISPLAY_ERROR 0 +#define WL_DISPLAY_DELETE_ID 1 + +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_ERROR_SINCE_VERSION 1 +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_SYNC_SINCE_VERSION 1 +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_registry + * @struct wl_registry_interface + */ +struct wl_registry_interface { + /** + * bind an object to the display + * + * Binds a new, client-created object to the server using the + * specified name as the identifier. + * @param name unique numeric name of the object + * @param interface name of the objects interface + * @param version version of the objects interface + * @param id bounded object + */ + void (*bind)(struct wl_client *client, + struct wl_resource *resource, + uint32_t name, + const char *interface, uint32_t version, uint32_t id); +}; + +#define WL_REGISTRY_GLOBAL 0 +#define WL_REGISTRY_GLOBAL_REMOVE 1 + +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_BIND_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_registry + * Sends an global event to the client owning the resource. + * @param resource_ The client's resource + * @param name numeric name of the global object + * @param interface interface implemented by the object + * @param version interface version + */ +static inline void +wl_registry_send_global(struct wl_resource *resource_, uint32_t name, const char *interface, uint32_t version) +{ + wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL, name, interface, version); +} + +/** + * @ingroup iface_wl_registry + * Sends an global_remove event to the client owning the resource. + * @param resource_ The client's resource + * @param name numeric name of the global object + */ +static inline void +wl_registry_send_global_remove(struct wl_resource *resource_, uint32_t name) +{ + wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL_REMOVE, name); +} + +#define WL_CALLBACK_DONE 0 + +/** + * @ingroup iface_wl_callback + */ +#define WL_CALLBACK_DONE_SINCE_VERSION 1 + + +/** + * @ingroup iface_wl_callback + * Sends an done event to the client owning the resource. + * @param resource_ The client's resource + * @param callback_data request-specific data for the callback + */ +static inline void +wl_callback_send_done(struct wl_resource *resource_, uint32_t callback_data) +{ + wl_resource_post_event(resource_, WL_CALLBACK_DONE, callback_data); +} + +/** + * @ingroup iface_wl_compositor + * @struct wl_compositor_interface + */ +struct wl_compositor_interface { + /** + * create new surface + * + * Ask the compositor to create a new surface. + * @param id the new surface + */ + void (*create_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * create new region + * + * Ask the compositor to create a new region. + * @param id the new region + */ + void (*create_region)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); +}; + + +/** + * @ingroup iface_wl_compositor + */ +#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_compositor + */ +#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shm_pool + * @struct wl_shm_pool_interface + */ +struct wl_shm_pool_interface { + /** + * create a buffer from the pool + * + * Create a wl_buffer object from the pool. + * + * The buffer is created offset bytes into the pool and has width + * and height as specified. The stride argument specifies the + * number of bytes from the beginning of one row to the beginning + * of the next. The format is the pixel format of the buffer and + * must be one of those advertised through the wl_shm.format event. + * + * A buffer will keep a reference to the pool it was created from + * so it is valid to destroy the pool immediately after creating a + * buffer from it. + * @param id buffer to create + * @param offset buffer byte offset within the pool + * @param width buffer width, in pixels + * @param height buffer height, in pixels + * @param stride number of bytes from the beginning of one row to the beginning of the next row + * @param format buffer pixel format + */ + void (*create_buffer)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + int32_t offset, + int32_t width, + int32_t height, + int32_t stride, + uint32_t format); + /** + * destroy the pool + * + * Destroy the shared memory pool. + * + * The mmapped memory will be released when all buffers that have + * been created from this pool are gone. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * change the size of the pool mapping + * + * This request will cause the server to remap the backing memory + * for the pool from the file descriptor passed when the pool was + * created, but using the new size. This request can only be used + * to make the pool bigger. + * @param size new size of the pool, in bytes + */ + void (*resize)(struct wl_client *client, + struct wl_resource *resource, + int32_t size); +}; + + +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 + +#ifndef WL_SHM_ERROR_ENUM +#define WL_SHM_ERROR_ENUM +/** + * @ingroup iface_wl_shm + * wl_shm error values + * + * These errors can be emitted in response to wl_shm requests. + */ +enum wl_shm_error { + /** + * buffer format is not known + */ + WL_SHM_ERROR_INVALID_FORMAT = 0, + /** + * invalid size or stride during pool or buffer creation + */ + WL_SHM_ERROR_INVALID_STRIDE = 1, + /** + * mmapping the file descriptor failed + */ + WL_SHM_ERROR_INVALID_FD = 2, +}; +#endif /* WL_SHM_ERROR_ENUM */ + +#ifndef WL_SHM_FORMAT_ENUM +#define WL_SHM_FORMAT_ENUM +/** + * @ingroup iface_wl_shm + * pixel formats + * + * This describes the memory layout of an individual pixel. + * + * All renderers should support argb8888 and xrgb8888 but any other + * formats are optional and may not be supported by the particular + * renderer in use. + * + * The drm format codes match the macros defined in drm_fourcc.h. + * The formats actually supported by the compositor will be + * reported by the format event. + */ +enum wl_shm_format { + /** + * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ARGB8888 = 0, + /** + * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XRGB8888 = 1, + /** + * 8-bit color index format, [7:0] C + */ + WL_SHM_FORMAT_C8 = 0x20203843, + /** + * 8-bit RGB format, [7:0] R:G:B 3:3:2 + */ + WL_SHM_FORMAT_RGB332 = 0x38424752, + /** + * 8-bit BGR format, [7:0] B:G:R 2:3:3 + */ + WL_SHM_FORMAT_BGR233 = 0x38524742, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XRGB4444 = 0x32315258, + /** + * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XBGR4444 = 0x32314258, + /** + * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBX4444 = 0x32315852, + /** + * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRX4444 = 0x32315842, + /** + * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ARGB4444 = 0x32315241, + /** + * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ABGR4444 = 0x32314241, + /** + * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBA4444 = 0x32314152, + /** + * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRA4444 = 0x32314142, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XRGB1555 = 0x35315258, + /** + * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XBGR1555 = 0x35314258, + /** + * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBX5551 = 0x35315852, + /** + * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRX5551 = 0x35315842, + /** + * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ARGB1555 = 0x35315241, + /** + * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ABGR1555 = 0x35314241, + /** + * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBA5551 = 0x35314152, + /** + * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRA5551 = 0x35314142, + /** + * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian + */ + WL_SHM_FORMAT_RGB565 = 0x36314752, + /** + * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian + */ + WL_SHM_FORMAT_BGR565 = 0x36314742, + /** + * 24-bit RGB format, [23:0] R:G:B little endian + */ + WL_SHM_FORMAT_RGB888 = 0x34324752, + /** + * 24-bit BGR format, [23:0] B:G:R little endian + */ + WL_SHM_FORMAT_BGR888 = 0x34324742, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XBGR8888 = 0x34324258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBX8888 = 0x34325852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRX8888 = 0x34325842, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ABGR8888 = 0x34324241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBA8888 = 0x34324152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRA8888 = 0x34324142, + /** + * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XRGB2101010 = 0x30335258, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XBGR2101010 = 0x30334258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBX1010102 = 0x30335852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRX1010102 = 0x30335842, + /** + * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ARGB2101010 = 0x30335241, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ABGR2101010 = 0x30334241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBA1010102 = 0x30334152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRA1010102 = 0x30334142, + /** + * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YUYV = 0x56595559, + /** + * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YVYU = 0x55595659, + /** + * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_UYVY = 0x59565955, + /** + * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_VYUY = 0x59555956, + /** + * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian + */ + WL_SHM_FORMAT_AYUV = 0x56555941, + /** + * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV12 = 0x3231564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV21 = 0x3132564e, + /** + * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV16 = 0x3631564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV61 = 0x3136564e, + /** + * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV410 = 0x39565559, + /** + * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU410 = 0x39555659, + /** + * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV411 = 0x31315559, + /** + * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU411 = 0x31315659, + /** + * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV420 = 0x32315559, + /** + * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU420 = 0x32315659, + /** + * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV422 = 0x36315559, + /** + * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU422 = 0x36315659, + /** + * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV444 = 0x34325559, + /** + * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU444 = 0x34325659, +}; +#endif /* WL_SHM_FORMAT_ENUM */ + +/** + * @ingroup iface_wl_shm + * @struct wl_shm_interface + */ +struct wl_shm_interface { + /** + * create a shm pool + * + * Create a new wl_shm_pool object. + * + * The pool can be used to create shared memory based buffer + * objects. The server will mmap size bytes of the passed file + * descriptor, to use as backing memory for the pool. + * @param id pool to create + * @param fd file descriptor for the pool + * @param size pool size, in bytes + */ + void (*create_pool)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + int32_t fd, + int32_t size); +}; + +#define WL_SHM_FORMAT 0 + +/** + * @ingroup iface_wl_shm + */ +#define WL_SHM_FORMAT_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shm + */ +#define WL_SHM_CREATE_POOL_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shm + * Sends an format event to the client owning the resource. + * @param resource_ The client's resource + * @param format buffer pixel format + */ +static inline void +wl_shm_send_format(struct wl_resource *resource_, uint32_t format) +{ + wl_resource_post_event(resource_, WL_SHM_FORMAT, format); +} + +/** + * @ingroup iface_wl_buffer + * @struct wl_buffer_interface + */ +struct wl_buffer_interface { + /** + * destroy a buffer + * + * Destroy a buffer. If and how you need to release the backing + * storage is defined by the buffer factory interface. + * + * For possible side-effects to a surface, see wl_surface.attach. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_BUFFER_RELEASE 0 + +/** + * @ingroup iface_wl_buffer + */ +#define WL_BUFFER_RELEASE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_buffer + */ +#define WL_BUFFER_DESTROY_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_buffer + * Sends an release event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_buffer_send_release(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_BUFFER_RELEASE); +} + +#ifndef WL_DATA_OFFER_ERROR_ENUM +#define WL_DATA_OFFER_ERROR_ENUM +enum wl_data_offer_error { + /** + * finish request was called untimely + */ + WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, + /** + * action mask contains invalid values + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, + /** + * action argument has an invalid value + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, + /** + * offer doesn't accept this request + */ + WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, +}; +#endif /* WL_DATA_OFFER_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_offer + * @struct wl_data_offer_interface + */ +struct wl_data_offer_interface { + /** + * accept one of the offered mime types + * + * Indicate that the client can accept the given mime type, or + * NULL for not accepted. + * + * For objects of version 2 or older, this request is used by the + * client to give feedback whether the client can receive the given + * mime type, or NULL if none is accepted; the feedback does not + * determine whether the drag-and-drop operation succeeds or not. + * + * For objects of version 3 or newer, this request determines the + * final result of the drag-and-drop operation. If the end result + * is that no mime types were accepted, the drag-and-drop operation + * will be cancelled and the corresponding drag source will receive + * wl_data_source.cancelled. Clients may still use this event in + * conjunction with wl_data_source.action for feedback. + * @param serial serial number of the accept request + * @param mime_type mime type accepted by the client + */ + void (*accept)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + const char *mime_type); + /** + * request that the data is transferred + * + * To transfer the offered data, the client issues this request + * and indicates the mime type it wants to receive. The transfer + * happens through the passed file descriptor (typically created + * with the pipe system call). The source client writes the data in + * the mime type representation requested and then closes the file + * descriptor. + * + * The receiving client reads from the read end of the pipe until + * EOF and then closes its end, at which point the transfer is + * complete. + * + * This request may happen multiple times for different mime types, + * both before and after wl_data_device.drop. Drag-and-drop + * destination clients may preemptively fetch data or examine it + * more closely to determine acceptance. + * @param mime_type mime type desired by receiver + * @param fd file descriptor for data transfer + */ + void (*receive)(struct wl_client *client, + struct wl_resource *resource, + const char *mime_type, + int32_t fd); + /** + * destroy data offer + * + * Destroy the data offer. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * the offer will no longer be used + * + * Notifies the compositor that the drag destination successfully + * finished the drag-and-drop operation. + * + * Upon receiving this request, the compositor will emit + * wl_data_source.dnd_finished on the drag source client. + * + * It is a client error to perform other requests than + * wl_data_offer.destroy after this one. It is also an error to + * perform this request after a NULL mime type has been set in + * wl_data_offer.accept or no action was received through + * wl_data_offer.action. + * @since 3 + */ + void (*finish)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the available/preferred drag-and-drop actions + * + * Sets the actions that the destination side client supports for + * this operation. This request may trigger the emission of + * wl_data_source.action and wl_data_offer.action events if the + * compositor needs to change the selected action. + * + * This request can be called multiple times throughout the + * drag-and-drop operation, typically in response to + * wl_data_device.enter or wl_data_device.motion events. + * + * This request determines the final result of the drag-and-drop + * operation. If the end result is that no action is accepted, the + * drag source will receive wl_drag_source.cancelled. + * + * The dnd_actions argument must contain only values expressed in + * the wl_data_device_manager.dnd_actions enum, and the + * preferred_action argument must only contain one of those values + * set, otherwise it will result in a protocol error. + * + * While managing an "ask" action, the destination drag-and-drop + * client may perform further wl_data_offer.receive requests, and + * is expected to perform one last wl_data_offer.set_actions + * request with a preferred action other than "ask" (and optionally + * wl_data_offer.accept) before requesting wl_data_offer.finish, in + * order to convey the action selected by the user. If the + * preferred action is not in the wl_data_offer.source_actions + * mask, an error will be raised. + * + * If the "ask" action is dismissed (e.g. user cancellation), the + * client is expected to perform wl_data_offer.destroy right away. + * + * This request can only be made on drag-and-drop offers, a + * protocol error will be raised otherwise. + * @param dnd_actions actions supported by the destination client + * @param preferred_action action preferred by the destination client + * @since 3 + */ + void (*set_actions)(struct wl_client *client, + struct wl_resource *resource, + uint32_t dnd_actions, + uint32_t preferred_action); +}; + +#define WL_DATA_OFFER_OFFER 0 +#define WL_DATA_OFFER_SOURCE_ACTIONS 1 +#define WL_DATA_OFFER_ACTION 2 + +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_offer + * Sends an offer event to the client owning the resource. + * @param resource_ The client's resource + * @param mime_type offered mime type + */ +static inline void +wl_data_offer_send_offer(struct wl_resource *resource_, const char *mime_type) +{ + wl_resource_post_event(resource_, WL_DATA_OFFER_OFFER, mime_type); +} + +/** + * @ingroup iface_wl_data_offer + * Sends an source_actions event to the client owning the resource. + * @param resource_ The client's resource + * @param source_actions actions offered by the data source + */ +static inline void +wl_data_offer_send_source_actions(struct wl_resource *resource_, uint32_t source_actions) +{ + wl_resource_post_event(resource_, WL_DATA_OFFER_SOURCE_ACTIONS, source_actions); +} + +/** + * @ingroup iface_wl_data_offer + * Sends an action event to the client owning the resource. + * @param resource_ The client's resource + * @param dnd_action action selected by the compositor + */ +static inline void +wl_data_offer_send_action(struct wl_resource *resource_, uint32_t dnd_action) +{ + wl_resource_post_event(resource_, WL_DATA_OFFER_ACTION, dnd_action); +} + +#ifndef WL_DATA_SOURCE_ERROR_ENUM +#define WL_DATA_SOURCE_ERROR_ENUM +enum wl_data_source_error { + /** + * action mask contains invalid values + */ + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, + /** + * source doesn't accept this request + */ + WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, +}; +#endif /* WL_DATA_SOURCE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_source + * @struct wl_data_source_interface + */ +struct wl_data_source_interface { + /** + * add an offered mime type + * + * This request adds a mime type to the set of mime types + * advertised to targets. Can be called several times to offer + * multiple types. + * @param mime_type mime type offered by the data source + */ + void (*offer)(struct wl_client *client, + struct wl_resource *resource, + const char *mime_type); + /** + * destroy the data source + * + * Destroy the data source. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the available drag-and-drop actions + * + * Sets the actions that the source side client supports for this + * operation. This request may trigger wl_data_source.action and + * wl_data_offer.action events if the compositor needs to change + * the selected action. + * + * The dnd_actions argument must contain only values expressed in + * the wl_data_device_manager.dnd_actions enum, otherwise it will + * result in a protocol error. + * + * This request must be made once only, and can only be made on + * sources used in drag-and-drop, so it must be performed before + * wl_data_device.start_drag. Attempting to use the source other + * than for drag-and-drop will raise a protocol error. + * @param dnd_actions actions supported by the data source + * @since 3 + */ + void (*set_actions)(struct wl_client *client, + struct wl_resource *resource, + uint32_t dnd_actions); +}; + +#define WL_DATA_SOURCE_TARGET 0 +#define WL_DATA_SOURCE_SEND 1 +#define WL_DATA_SOURCE_CANCELLED 2 +#define WL_DATA_SOURCE_DND_DROP_PERFORMED 3 +#define WL_DATA_SOURCE_DND_FINISHED 4 +#define WL_DATA_SOURCE_ACTION 5 + +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_source + * Sends an target event to the client owning the resource. + * @param resource_ The client's resource + * @param mime_type mime type accepted by the target + */ +static inline void +wl_data_source_send_target(struct wl_resource *resource_, const char *mime_type) +{ + wl_resource_post_event(resource_, WL_DATA_SOURCE_TARGET, mime_type); +} + +/** + * @ingroup iface_wl_data_source + * Sends an send event to the client owning the resource. + * @param resource_ The client's resource + * @param mime_type mime type for the data + * @param fd file descriptor for the data + */ +static inline void +wl_data_source_send_send(struct wl_resource *resource_, const char *mime_type, int32_t fd) +{ + wl_resource_post_event(resource_, WL_DATA_SOURCE_SEND, mime_type, fd); +} + +/** + * @ingroup iface_wl_data_source + * Sends an cancelled event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_data_source_send_cancelled(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_DATA_SOURCE_CANCELLED); +} + +/** + * @ingroup iface_wl_data_source + * Sends an dnd_drop_performed event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_data_source_send_dnd_drop_performed(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_DATA_SOURCE_DND_DROP_PERFORMED); +} + +/** + * @ingroup iface_wl_data_source + * Sends an dnd_finished event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_data_source_send_dnd_finished(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_DATA_SOURCE_DND_FINISHED); +} + +/** + * @ingroup iface_wl_data_source + * Sends an action event to the client owning the resource. + * @param resource_ The client's resource + * @param dnd_action action selected by the compositor + */ +static inline void +wl_data_source_send_action(struct wl_resource *resource_, uint32_t dnd_action) +{ + wl_resource_post_event(resource_, WL_DATA_SOURCE_ACTION, dnd_action); +} + +#ifndef WL_DATA_DEVICE_ERROR_ENUM +#define WL_DATA_DEVICE_ERROR_ENUM +enum wl_data_device_error { + /** + * given wl_surface has another role + */ + WL_DATA_DEVICE_ERROR_ROLE = 0, +}; +#endif /* WL_DATA_DEVICE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_device + * @struct wl_data_device_interface + */ +struct wl_data_device_interface { + /** + * start drag-and-drop operation + * + * This request asks the compositor to start a drag-and-drop + * operation on behalf of the client. + * + * The source argument is the data source that provides the data + * for the eventual data transfer. If source is NULL, enter, leave + * and motion events are sent only to the client that initiated the + * drag and the client is expected to handle the data passing + * internally. + * + * The origin surface is the surface where the drag originates and + * the client must have an active implicit grab that matches the + * serial. + * + * The icon surface is an optional (can be NULL) surface that + * provides an icon to be moved around with the cursor. Initially, + * the top-left corner of the icon surface is placed at the cursor + * hotspot, but subsequent wl_surface.attach request can move the + * relative position. Attach requests must be confirmed with + * wl_surface.commit as usual. The icon surface is given the role + * of a drag-and-drop icon. If the icon surface already has another + * role, it raises a protocol error. + * + * The current and pending input regions of the icon wl_surface are + * cleared, and wl_surface.set_input_region is ignored until the + * wl_surface is no longer used as the icon surface. When the use + * as an icon ends, the current and pending input regions become + * undefined, and the wl_surface is unmapped. + * @param source data source for the eventual transfer + * @param origin surface where the drag originates + * @param icon drag-and-drop icon surface + * @param serial serial number of the implicit grab on the origin + */ + void (*start_drag)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *source, + struct wl_resource *origin, + struct wl_resource *icon, + uint32_t serial); + /** + * copy data to the selection + * + * This request asks the compositor to set the selection to the + * data from the source on behalf of the client. + * + * To unset the selection, set the source to NULL. + * @param source data source for the selection + * @param serial serial number of the event that triggered this request + */ + void (*set_selection)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *source, + uint32_t serial); + /** + * destroy data device + * + * This request destroys the data device. + * @since 2 + */ + void (*release)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_DATA_DEVICE_DATA_OFFER 0 +#define WL_DATA_DEVICE_ENTER 1 +#define WL_DATA_DEVICE_LEAVE 2 +#define WL_DATA_DEVICE_MOTION 3 +#define WL_DATA_DEVICE_DROP 4 +#define WL_DATA_DEVICE_SELECTION 5 + +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 + +/** + * @ingroup iface_wl_data_device + * Sends an data_offer event to the client owning the resource. + * @param resource_ The client's resource + * @param id the new data_offer object + */ +static inline void +wl_data_device_send_data_offer(struct wl_resource *resource_, struct wl_resource *id) +{ + wl_resource_post_event(resource_, WL_DATA_DEVICE_DATA_OFFER, id); +} + +/** + * @ingroup iface_wl_data_device + * Sends an enter event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the enter event + * @param surface client surface entered + * @param x surface-local x coordinate + * @param y surface-local y coordinate + * @param id source data_offer object + */ +static inline void +wl_data_device_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y, struct wl_resource *id) +{ + wl_resource_post_event(resource_, WL_DATA_DEVICE_ENTER, serial, surface, x, y, id); +} + +/** + * @ingroup iface_wl_data_device + * Sends an leave event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_data_device_send_leave(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_DATA_DEVICE_LEAVE); +} + +/** + * @ingroup iface_wl_data_device + * Sends an motion event to the client owning the resource. + * @param resource_ The client's resource + * @param time timestamp with millisecond granularity + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ +static inline void +wl_data_device_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t x, wl_fixed_t y) +{ + wl_resource_post_event(resource_, WL_DATA_DEVICE_MOTION, time, x, y); +} + +/** + * @ingroup iface_wl_data_device + * Sends an drop event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_data_device_send_drop(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_DATA_DEVICE_DROP); +} + +/** + * @ingroup iface_wl_data_device + * Sends an selection event to the client owning the resource. + * @param resource_ The client's resource + * @param id selection data_offer object + */ +static inline void +wl_data_device_send_selection(struct wl_resource *resource_, struct wl_resource *id) +{ + wl_resource_post_event(resource_, WL_DATA_DEVICE_SELECTION, id); +} + +#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +/** + * @ingroup iface_wl_data_device_manager + * drag and drop actions + * + * This is a bitmask of the available/preferred actions in a + * drag-and-drop operation. + * + * In the compositor, the selected action is a result of matching the + * actions offered by the source and destination sides. "action" events + * with a "none" action will be sent to both source and destination if + * there is no match. All further checks will effectively happen on + * (source actions ∩ destination actions). + * + * In addition, compositors may also pick different actions in + * reaction to key modifiers being pressed. One common design that + * is used in major toolkits (and the behavior recommended for + * compositors) is: + * + * - If no modifiers are pressed, the first match (in bit order) + * will be used. + * - Pressing Shift selects "move", if enabled in the mask. + * - Pressing Control selects "copy", if enabled in the mask. + * + * Behavior beyond that is considered implementation-dependent. + * Compositors may for example bind other modifiers (like Alt/Meta) + * or drags initiated with other buttons than BTN_LEFT to specific + * actions (e.g. "ask"). + */ +enum wl_data_device_manager_dnd_action { + /** + * no action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, + /** + * copy action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, + /** + * move action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, + /** + * ask action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, +}; +#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ + +/** + * @ingroup iface_wl_data_device_manager + * @struct wl_data_device_manager_interface + */ +struct wl_data_device_manager_interface { + /** + * create a new data source + * + * Create a new data source. + * @param id data source to create + */ + void (*create_data_source)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * create a new data device + * + * Create a new data device for a given seat. + * @param id data device to create + * @param seat seat associated with the data device + */ + void (*get_data_device)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *seat); +}; + + +/** + * @ingroup iface_wl_data_device_manager + */ +#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device_manager + */ +#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 + +#ifndef WL_SHELL_ERROR_ENUM +#define WL_SHELL_ERROR_ENUM +enum wl_shell_error { + /** + * given wl_surface has another role + */ + WL_SHELL_ERROR_ROLE = 0, +}; +#endif /* WL_SHELL_ERROR_ENUM */ + +/** + * @ingroup iface_wl_shell + * @struct wl_shell_interface + */ +struct wl_shell_interface { + /** + * create a shell surface from a surface + * + * Create a shell surface for an existing surface. This gives the + * wl_surface the role of a shell surface. If the wl_surface + * already has another role, it raises a protocol error. + * + * Only one shell surface can be associated with a given surface. + * @param id shell surface to create + * @param surface surface to be given the shell surface role + */ + void (*get_shell_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); +}; + + +/** + * @ingroup iface_wl_shell + */ +#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 + +#ifndef WL_SHELL_SURFACE_RESIZE_ENUM +#define WL_SHELL_SURFACE_RESIZE_ENUM +/** + * @ingroup iface_wl_shell_surface + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. The server may + * use this information to adapt its behavior, e.g. choose + * an appropriate cursor image. + */ +enum wl_shell_surface_resize { + /** + * no edge + */ + WL_SHELL_SURFACE_RESIZE_NONE = 0, + /** + * top edge + */ + WL_SHELL_SURFACE_RESIZE_TOP = 1, + /** + * bottom edge + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, + /** + * left edge + */ + WL_SHELL_SURFACE_RESIZE_LEFT = 4, + /** + * top and left edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, + /** + * bottom and left edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, + /** + * right edge + */ + WL_SHELL_SURFACE_RESIZE_RIGHT = 8, + /** + * top and right edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, + /** + * bottom and right edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, +}; +#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ + +#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM +#define WL_SHELL_SURFACE_TRANSIENT_ENUM +/** + * @ingroup iface_wl_shell_surface + * details of transient behaviour + * + * These flags specify details of the expected behaviour + * of transient surfaces. Used in the set_transient request. + */ +enum wl_shell_surface_transient { + /** + * do not set keyboard focus + */ + WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, +}; +#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ + +#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +/** + * @ingroup iface_wl_shell_surface + * different method to set the surface fullscreen + * + * Hints to indicate to the compositor how to deal with a conflict + * between the dimensions of the surface and the dimensions of the + * output. The compositor is free to ignore this parameter. + */ +enum wl_shell_surface_fullscreen_method { + /** + * no preference, apply default policy + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, + /** + * scale, preserve the surface's aspect ratio and center on output + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, + /** + * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, + /** + * no upscaling, center on output and add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, +}; +#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ + +/** + * @ingroup iface_wl_shell_surface + * @struct wl_shell_surface_interface + */ +struct wl_shell_surface_interface { + /** + * respond to a ping event + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. + * @param serial serial number of the ping event + */ + void (*pong)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); + /** + * start an interactive move + * + * Start a pointer-driven move of the surface. + * + * This request must be used in response to a button press event. + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * @param seat seat whose pointer is used + * @param serial serial number of the implicit grab on the pointer + */ + void (*move)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * start an interactive resize + * + * Start a pointer-driven resizing of the surface. + * + * This request must be used in response to a button press event. + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * @param seat seat whose pointer is used + * @param serial serial number of the implicit grab on the pointer + * @param edges which edge or corner is being dragged + */ + void (*resize)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + uint32_t edges); + /** + * make the surface a toplevel surface + * + * Map the surface as a toplevel surface. + * + * A toplevel surface is not fullscreen, maximized or transient. + */ + void (*set_toplevel)(struct wl_client *client, + struct wl_resource *resource); + /** + * make the surface a transient surface + * + * Map the surface relative to an existing surface. + * + * The x and y arguments specify the location of the upper left + * corner of the surface relative to the upper left corner of the + * parent surface, in surface-local coordinates. + * + * The flags argument controls details of the transient behaviour. + * @param parent parent surface + * @param x surface-local x coordinate + * @param y surface-local y coordinate + * @param flags transient surface behavior + */ + void (*set_transient)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent, + int32_t x, + int32_t y, + uint32_t flags); + /** + * make the surface a fullscreen surface + * + * Map the surface as a fullscreen surface. + * + * If an output parameter is given then the surface will be made + * fullscreen on that output. If the client does not specify the + * output then the compositor will apply its policy - usually + * choosing the output on which the surface has the biggest surface + * area. + * + * The client may specify a method to resolve a size conflict + * between the output size and the surface size - this is provided + * through the method parameter. + * + * The framerate parameter is used only when the method is set to + * "driver", to indicate the preferred framerate. A value of 0 + * indicates that the client does not care about framerate. The + * framerate is specified in mHz, that is framerate of 60000 is + * 60Hz. + * + * A method of "scale" or "driver" implies a scaling operation of + * the surface, either via a direct scaling operation or a change + * of the output mode. This will override any kind of output + * scaling, so that mapping a surface with a buffer size equal to + * the mode can fill the screen independent of buffer_scale. + * + * A method of "fill" means we don't scale up the buffer, however + * any output scale is applied. This means that you may run into an + * edge case where the application maps a buffer with the same size + * of the output mode but buffer_scale 1 (thus making a surface + * larger than the output). In this case it is allowed to downscale + * the results to fit the screen. + * + * The compositor must reply to this request with a configure event + * with the dimensions for the output on which the surface will be + * made fullscreen. + * @param method method for resolving size conflict + * @param framerate framerate in mHz + * @param output output on which the surface is to be fullscreen + */ + void (*set_fullscreen)(struct wl_client *client, + struct wl_resource *resource, + uint32_t method, + uint32_t framerate, + struct wl_resource *output); + /** + * make the surface a popup surface + * + * Map the surface as a popup. + * + * A popup surface is a transient surface with an added pointer + * grab. + * + * An existing implicit grab will be changed to owner-events mode, + * and the popup grab will continue after the implicit grab ends + * (i.e. releasing the mouse button does not cause the popup to be + * unmapped). + * + * The popup grab continues until the window is destroyed or a + * mouse button is pressed in any other client's window. A click in + * any of the client's surfaces is reported as normal, however, + * clicks in other clients' surfaces will be discarded and trigger + * the callback. + * + * The x and y arguments specify the location of the upper left + * corner of the surface relative to the upper left corner of the + * parent surface, in surface-local coordinates. + * @param seat seat whose pointer is used + * @param serial serial number of the implicit grab on the pointer + * @param parent parent surface + * @param x surface-local x coordinate + * @param y surface-local y coordinate + * @param flags transient surface behavior + */ + void (*set_popup)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + struct wl_resource *parent, + int32_t x, + int32_t y, + uint32_t flags); + /** + * make the surface a maximized surface + * + * Map the surface as a maximized surface. + * + * If an output parameter is given then the surface will be + * maximized on that output. If the client does not specify the + * output then the compositor will apply its policy - usually + * choosing the output on which the surface has the biggest surface + * area. + * + * The compositor will reply with a configure event telling the + * expected new surface size. The operation is completed on the + * next buffer attach to this surface. + * + * A maximized surface typically fills the entire output it is + * bound to, except for desktop elements such as panels. This is + * the main difference between a maximized shell surface and a + * fullscreen shell surface. + * + * The details depend on the compositor implementation. + * @param output output on which the surface is to be maximized + */ + void (*set_maximized)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output); + /** + * set surface title + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + * @param title surface title + */ + void (*set_title)(struct wl_client *client, + struct wl_resource *resource, + const char *title); + /** + * set surface class + * + * Set a class for the surface. + * + * The surface class identifies the general class of applications + * to which the surface belongs. A common convention is to use the + * file name (or the full path if it is a non-standard location) of + * the application's .desktop file as the class. + * @param class_ surface class + */ + void (*set_class)(struct wl_client *client, + struct wl_resource *resource, + const char *class_); +}; + +#define WL_SHELL_SURFACE_PING 0 +#define WL_SHELL_SURFACE_CONFIGURE 1 +#define WL_SHELL_SURFACE_POPUP_DONE 2 + +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shell_surface + * Sends an ping event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the ping + */ +static inline void +wl_shell_surface_send_ping(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, WL_SHELL_SURFACE_PING, serial); +} + +/** + * @ingroup iface_wl_shell_surface + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param edges how the surface was resized + * @param width new width of the surface + * @param height new height of the surface + */ +static inline void +wl_shell_surface_send_configure(struct wl_resource *resource_, uint32_t edges, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, WL_SHELL_SURFACE_CONFIGURE, edges, width, height); +} + +/** + * @ingroup iface_wl_shell_surface + * Sends an popup_done event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_shell_surface_send_popup_done(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_SHELL_SURFACE_POPUP_DONE); +} + +#ifndef WL_SURFACE_ERROR_ENUM +#define WL_SURFACE_ERROR_ENUM +/** + * @ingroup iface_wl_surface + * wl_surface error values + * + * These errors can be emitted in response to wl_surface requests. + */ +enum wl_surface_error { + /** + * buffer scale value is invalid + */ + WL_SURFACE_ERROR_INVALID_SCALE = 0, + /** + * buffer transform value is invalid + */ + WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, +}; +#endif /* WL_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_surface + * @struct wl_surface_interface + */ +struct wl_surface_interface { + /** + * delete surface + * + * Deletes the surface and invalidates its object ID. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the surface contents + * + * Set a buffer as the content of this surface. + * + * The new size of the surface is calculated based on the buffer + * size transformed by the inverse buffer_transform and the inverse + * buffer_scale. This means that the supplied buffer must be an + * integer multiple of the buffer_scale. + * + * The x and y arguments specify the location of the new pending + * buffer's upper left corner, relative to the current buffer's + * upper left corner, in surface-local coordinates. In other words, + * the x and y, combined with the new surface size define in which + * directions the surface's size changes. + * + * Surface contents are double-buffered state, see + * wl_surface.commit. + * + * The initial surface contents are void; there is no content. + * wl_surface.attach assigns the given wl_buffer as the pending + * wl_buffer. wl_surface.commit makes the pending wl_buffer the new + * surface contents, and the size of the surface becomes the size + * calculated from the wl_buffer, as described above. After commit, + * there is no pending buffer until the next attach. + * + * Committing a pending wl_buffer allows the compositor to read the + * pixels in the wl_buffer. The compositor may access the pixels at + * any time after the wl_surface.commit request. When the + * compositor will not access the pixels anymore, it will send the + * wl_buffer.release event. Only after receiving wl_buffer.release, + * the client may reuse the wl_buffer. A wl_buffer that has been + * attached and then replaced by another attach instead of + * committed will not receive a release event, and is not used by + * the compositor. + * + * Destroying the wl_buffer after wl_buffer.release does not change + * the surface contents. However, if the client destroys the + * wl_buffer before receiving the wl_buffer.release event, the + * surface contents become undefined immediately. + * + * If wl_surface.attach is sent with a NULL wl_buffer, the + * following wl_surface.commit will remove the surface content. + * @param buffer buffer of surface contents + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*attach)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer, + int32_t x, + int32_t y); + /** + * mark part of the surface damaged + * + * This request is used to describe the regions where the pending + * buffer is different from the current surface contents, and where + * the surface therefore needs to be repainted. The compositor + * ignores the parts of the damage that fall outside of the + * surface. + * + * Damage is double-buffered state, see wl_surface.commit. + * + * The damage rectangle is specified in surface-local coordinates, + * where x and y specify the upper left corner of the damage + * rectangle. + * + * The initial value for pending damage is empty: no damage. + * wl_surface.damage adds pending damage: the new pending damage is + * the union of old pending damage and the given rectangle. + * + * wl_surface.commit assigns pending damage as the current damage, + * and clears pending damage. The server will clear the current + * damage as it repaints the surface. + * + * Alternatively, damage can be posted with + * wl_surface.damage_buffer which uses buffer coordinates instead + * of surface coordinates, and is probably the preferred and + * intuitive way of doing this. + * @param x surface-local x coordinate + * @param y surface-local y coordinate + * @param width width of damage rectangle + * @param height height of damage rectangle + */ + void (*damage)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * request a frame throttling hint + * + * Request a notification when it is a good time to start drawing + * a new frame, by creating a frame callback. This is useful for + * throttling redrawing operations, and driving animations. + * + * When a client is animating on a wl_surface, it can use the + * 'frame' request to get notified when it is a good time to draw + * and commit the next frame of animation. If the client commits an + * update earlier than that, it is likely that some updates will + * not make it to the display, and the client is wasting resources + * by drawing too often. + * + * The frame request will take effect on the next + * wl_surface.commit. The notification will only be posted for one + * frame unless requested again. For a wl_surface, the + * notifications are posted in the order the frame requests were + * committed. + * + * The server must send the notifications so that a client will not + * send excessive updates, while still allowing the highest + * possible update rate for clients that wait for the reply before + * drawing again. The server should give some time for the client + * to draw and commit after sending the frame callback events to + * let it hit the next output refresh. + * + * A server should avoid signaling the frame callbacks if the + * surface is not visible in any way, e.g. the surface is + * off-screen, or completely obscured by other opaque surfaces. + * + * The object returned by this request will be destroyed by the + * compositor after the callback is fired and as such the client + * must not attempt to use it after that point. + * + * The callback_data passed in the callback is the current time, in + * milliseconds, with an undefined base. + * @param callback callback object for the frame request + */ + void (*frame)(struct wl_client *client, + struct wl_resource *resource, + uint32_t callback); + /** + * set opaque region + * + * This request sets the region of the surface that contains + * opaque content. + * + * The opaque region is an optimization hint for the compositor + * that lets it optimize the redrawing of content behind opaque + * regions. Setting an opaque region is not required for correct + * behaviour, but marking transparent content as opaque will result + * in repaint artifacts. + * + * The opaque region is specified in surface-local coordinates. + * + * The compositor ignores the parts of the opaque region that fall + * outside of the surface. + * + * Opaque region is double-buffered state, see wl_surface.commit. + * + * wl_surface.set_opaque_region changes the pending opaque region. + * wl_surface.commit copies the pending region to the current + * region. Otherwise, the pending and current regions are never + * changed. + * + * The initial value for an opaque region is empty. Setting the + * pending opaque region has copy semantics, and the wl_region + * object can be destroyed immediately. A NULL wl_region causes the + * pending opaque region to be set to empty. + * @param region opaque region of the surface + */ + void (*set_opaque_region)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *region); + /** + * set input region + * + * This request sets the region of the surface that can receive + * pointer and touch events. + * + * Input events happening outside of this region will try the next + * surface in the server surface stack. The compositor ignores the + * parts of the input region that fall outside of the surface. + * + * The input region is specified in surface-local coordinates. + * + * Input region is double-buffered state, see wl_surface.commit. + * + * wl_surface.set_input_region changes the pending input region. + * wl_surface.commit copies the pending region to the current + * region. Otherwise the pending and current regions are never + * changed, except cursor and icon surfaces are special cases, see + * wl_pointer.set_cursor and wl_data_device.start_drag. + * + * The initial value for an input region is infinite. That means + * the whole surface will accept input. Setting the pending input + * region has copy semantics, and the wl_region object can be + * destroyed immediately. A NULL wl_region causes the input region + * to be set to infinite. + * @param region input region of the surface + */ + void (*set_input_region)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *region); + /** + * commit pending surface state + * + * Surface state (input, opaque, and damage regions, attached + * buffers, etc.) is double-buffered. Protocol requests modify the + * pending state, as opposed to the current state in use by the + * compositor. A commit request atomically applies all pending + * state, replacing the current state. After commit, the new + * pending state is as documented for each related request. + * + * On commit, a pending wl_buffer is applied first, and all other + * state second. This means that all coordinates in double-buffered + * state are relative to the new wl_buffer coming into use, except + * for wl_surface.attach itself. If there is no pending wl_buffer, + * the coordinates are relative to the current surface contents. + * + * All requests that need a commit to become effective are + * documented to affect double-buffered state. + * + * Other interfaces may add further double-buffered surface state. + */ + void (*commit)(struct wl_client *client, + struct wl_resource *resource); + /** + * sets the buffer transformation + * + * This request sets an optional transformation on how the + * compositor interprets the contents of the buffer attached to the + * surface. The accepted values for the transform parameter are the + * values for wl_output.transform. + * + * Buffer transform is double-buffered state, see + * wl_surface.commit. + * + * A newly created surface has its buffer transformation set to + * normal. + * + * wl_surface.set_buffer_transform changes the pending buffer + * transformation. wl_surface.commit copies the pending buffer + * transformation to the current one. Otherwise, the pending and + * current values are never changed. + * + * The purpose of this request is to allow clients to render + * content according to the output transform, thus permitting the + * compositor to use certain optimizations even if the display is + * rotated. Using hardware overlays and scanning out a client + * buffer for fullscreen surfaces are examples of such + * optimizations. Those optimizations are highly dependent on the + * compositor implementation, so the use of this request should be + * considered on a case-by-case basis. + * + * Note that if the transform value includes 90 or 270 degree + * rotation, the width of the buffer will become the surface height + * and the height of the buffer will become the surface width. + * + * If transform is not one of the values from the + * wl_output.transform enum the invalid_transform protocol error is + * raised. + * @param transform transform for interpreting buffer contents + * @since 2 + */ + void (*set_buffer_transform)(struct wl_client *client, + struct wl_resource *resource, + int32_t transform); + /** + * sets the buffer scaling factor + * + * This request sets an optional scaling factor on how the + * compositor interprets the contents of the buffer attached to the + * window. + * + * Buffer scale is double-buffered state, see wl_surface.commit. + * + * A newly created surface has its buffer scale set to 1. + * + * wl_surface.set_buffer_scale changes the pending buffer scale. + * wl_surface.commit copies the pending buffer scale to the current + * one. Otherwise, the pending and current values are never + * changed. + * + * The purpose of this request is to allow clients to supply higher + * resolution buffer data for use on high resolution outputs. It is + * intended that you pick the same buffer scale as the scale of the + * output that the surface is displayed on. This means the + * compositor can avoid scaling when rendering the surface on that + * output. + * + * Note that if the scale is larger than 1, then you have to attach + * a buffer that is larger (by a factor of scale in each dimension) + * than the desired surface size. + * + * If scale is not positive the invalid_scale protocol error is + * raised. + * @param scale positive scale for interpreting buffer contents + * @since 3 + */ + void (*set_buffer_scale)(struct wl_client *client, + struct wl_resource *resource, + int32_t scale); + /** + * mark part of the surface damaged using buffer coordinates + * + * This request is used to describe the regions where the pending + * buffer is different from the current surface contents, and where + * the surface therefore needs to be repainted. The compositor + * ignores the parts of the damage that fall outside of the + * surface. + * + * Damage is double-buffered state, see wl_surface.commit. + * + * The damage rectangle is specified in buffer coordinates, where x + * and y specify the upper left corner of the damage rectangle. + * + * The initial value for pending damage is empty: no damage. + * wl_surface.damage_buffer adds pending damage: the new pending + * damage is the union of old pending damage and the given + * rectangle. + * + * wl_surface.commit assigns pending damage as the current damage, + * and clears pending damage. The server will clear the current + * damage as it repaints the surface. + * + * This request differs from wl_surface.damage in only one way - it + * takes damage in buffer coordinates instead of surface-local + * coordinates. While this generally is more intuitive than surface + * coordinates, it is especially desirable when using wp_viewport + * or when a drawing library (like EGL) is unaware of buffer scale + * and buffer transform. + * + * Note: Because buffer transformation changes and damage requests + * may be interleaved in the protocol stream, it is impossible to + * determine the actual mapping between surface and buffer damage + * until wl_surface.commit time. Therefore, compositors wishing to + * take both kinds of damage into account will have to accumulate + * damage from the two requests separately and only transform from + * one to the other after receiving the wl_surface.commit. + * @param x buffer-local x coordinate + * @param y buffer-local y coordinate + * @param width width of damage rectangle + * @param height height of damage rectangle + * @since 4 + */ + void (*damage_buffer)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); +}; + +#define WL_SURFACE_ENTER 0 +#define WL_SURFACE_LEAVE 1 + +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_LEAVE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_ATTACH_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DAMAGE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_FRAME_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_COMMIT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 + +/** + * @ingroup iface_wl_surface + * Sends an enter event to the client owning the resource. + * @param resource_ The client's resource + * @param output output entered by the surface + */ +static inline void +wl_surface_send_enter(struct wl_resource *resource_, struct wl_resource *output) +{ + wl_resource_post_event(resource_, WL_SURFACE_ENTER, output); +} + +/** + * @ingroup iface_wl_surface + * Sends an leave event to the client owning the resource. + * @param resource_ The client's resource + * @param output output left by the surface + */ +static inline void +wl_surface_send_leave(struct wl_resource *resource_, struct wl_resource *output) +{ + wl_resource_post_event(resource_, WL_SURFACE_LEAVE, output); +} + +#ifndef WL_SEAT_CAPABILITY_ENUM +#define WL_SEAT_CAPABILITY_ENUM +/** + * @ingroup iface_wl_seat + * seat capability bitmask + * + * This is a bitmask of capabilities this seat has; if a member is + * set, then it is present on the seat. + */ +enum wl_seat_capability { + /** + * the seat has pointer devices + */ + WL_SEAT_CAPABILITY_POINTER = 1, + /** + * the seat has one or more keyboards + */ + WL_SEAT_CAPABILITY_KEYBOARD = 2, + /** + * the seat has touch devices + */ + WL_SEAT_CAPABILITY_TOUCH = 4, +}; +#endif /* WL_SEAT_CAPABILITY_ENUM */ + +/** + * @ingroup iface_wl_seat + * @struct wl_seat_interface + */ +struct wl_seat_interface { + /** + * return pointer object + * + * The ID provided will be initialized to the wl_pointer + * interface for this seat. + * + * This request only takes effect if the seat has the pointer + * capability, or has had the pointer capability in the past. It is + * a protocol violation to issue this request on a seat that has + * never had the pointer capability. + * @param id seat pointer + */ + void (*get_pointer)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * return keyboard object + * + * The ID provided will be initialized to the wl_keyboard + * interface for this seat. + * + * This request only takes effect if the seat has the keyboard + * capability, or has had the keyboard capability in the past. It + * is a protocol violation to issue this request on a seat that has + * never had the keyboard capability. + * @param id seat keyboard + */ + void (*get_keyboard)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * return touch object + * + * The ID provided will be initialized to the wl_touch interface + * for this seat. + * + * This request only takes effect if the seat has the touch + * capability, or has had the touch capability in the past. It is a + * protocol violation to issue this request on a seat that has + * never had the touch capability. + * @param id seat touch interface + */ + void (*get_touch)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * release the seat object + * + * Using this request a client can tell the server that it is not + * going to use the seat object anymore. + * @since 5 + */ + void (*release)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_SEAT_CAPABILITIES 0 +#define WL_SEAT_NAME 1 + +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_NAME_SINCE_VERSION 2 + +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_POINTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_RELEASE_SINCE_VERSION 5 + +/** + * @ingroup iface_wl_seat + * Sends an capabilities event to the client owning the resource. + * @param resource_ The client's resource + * @param capabilities capabilities of the seat + */ +static inline void +wl_seat_send_capabilities(struct wl_resource *resource_, uint32_t capabilities) +{ + wl_resource_post_event(resource_, WL_SEAT_CAPABILITIES, capabilities); +} + +/** + * @ingroup iface_wl_seat + * Sends an name event to the client owning the resource. + * @param resource_ The client's resource + * @param name seat identifier + */ +static inline void +wl_seat_send_name(struct wl_resource *resource_, const char *name) +{ + wl_resource_post_event(resource_, WL_SEAT_NAME, name); +} + +#ifndef WL_POINTER_ERROR_ENUM +#define WL_POINTER_ERROR_ENUM +enum wl_pointer_error { + /** + * given wl_surface has another role + */ + WL_POINTER_ERROR_ROLE = 0, +}; +#endif /* WL_POINTER_ERROR_ENUM */ + +#ifndef WL_POINTER_BUTTON_STATE_ENUM +#define WL_POINTER_BUTTON_STATE_ENUM +/** + * @ingroup iface_wl_pointer + * physical button state + * + * Describes the physical state of a button that produced the button + * event. + */ +enum wl_pointer_button_state { + /** + * the button is not pressed + */ + WL_POINTER_BUTTON_STATE_RELEASED = 0, + /** + * the button is pressed + */ + WL_POINTER_BUTTON_STATE_PRESSED = 1, +}; +#endif /* WL_POINTER_BUTTON_STATE_ENUM */ + +#ifndef WL_POINTER_AXIS_ENUM +#define WL_POINTER_AXIS_ENUM +/** + * @ingroup iface_wl_pointer + * axis types + * + * Describes the axis types of scroll events. + */ +enum wl_pointer_axis { + /** + * vertical axis + */ + WL_POINTER_AXIS_VERTICAL_SCROLL = 0, + /** + * horizontal axis + */ + WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, +}; +#endif /* WL_POINTER_AXIS_ENUM */ + +#ifndef WL_POINTER_AXIS_SOURCE_ENUM +#define WL_POINTER_AXIS_SOURCE_ENUM +/** + * @ingroup iface_wl_pointer + * axis source types + * + * Describes the source types for axis events. This indicates to the + * client how an axis event was physically generated; a client may + * adjust the user interface accordingly. For example, scroll events + * from a "finger" source may be in a smooth coordinate space with + * kinetic scrolling whereas a "wheel" source may be in discrete steps + * of a number of lines. + * + * The "continuous" axis source is a device generating events in a + * continuous coordinate space, but using something other than a + * finger. One example for this source is button-based scrolling where + * the vertical motion of a device is converted to scroll events while + * a button is held down. + */ +enum wl_pointer_axis_source { + /** + * a physical wheel + */ + WL_POINTER_AXIS_SOURCE_WHEEL = 0, + /** + * finger on a touch surface + */ + WL_POINTER_AXIS_SOURCE_FINGER = 1, + /** + * continuous coordinate space + */ + WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, +}; +#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ + +/** + * @ingroup iface_wl_pointer + * @struct wl_pointer_interface + */ +struct wl_pointer_interface { + /** + * set the pointer surface + * + * Set the pointer surface, i.e., the surface that contains the + * pointer image (cursor). This request gives the surface the role + * of a cursor. If the surface already has another role, it raises + * a protocol error. + * + * The cursor actually changes only if the pointer focus for this + * device is one of the requesting client's surfaces or the surface + * parameter is the current pointer surface. If there was a + * previous surface set with this request it is replaced. If + * surface is NULL, the pointer image is hidden. + * + * The parameters hotspot_x and hotspot_y define the position of + * the pointer surface relative to the pointer location. Its + * top-left corner is always at (x, y) - (hotspot_x, hotspot_y), + * where (x, y) are the coordinates of the pointer location, in + * surface-local coordinates. + * + * On surface.attach requests to the pointer surface, hotspot_x and + * hotspot_y are decremented by the x and y parameters passed to + * the request. Attach must be confirmed by wl_surface.commit as + * usual. + * + * The hotspot can also be updated by passing the currently set + * pointer surface to this request with new values for hotspot_x + * and hotspot_y. + * + * The current and pending input regions of the wl_surface are + * cleared, and wl_surface.set_input_region is ignored until the + * wl_surface is no longer used as the cursor. When the use as a + * cursor ends, the current and pending input regions become + * undefined, and the wl_surface is unmapped. + * @param serial serial number of the enter event + * @param surface pointer surface + * @param hotspot_x surface-local x coordinate + * @param hotspot_y surface-local y coordinate + */ + void (*set_cursor)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + struct wl_resource *surface, + int32_t hotspot_x, + int32_t hotspot_y); + /** + * release the pointer object + * + * Using this request a client can tell the server that it is not + * going to use the pointer object anymore. + * + * This request destroys the pointer proxy object, so clients must + * not call wl_pointer_destroy() after using this request. + * @since 3 + */ + void (*release)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_POINTER_ENTER 0 +#define WL_POINTER_LEAVE 1 +#define WL_POINTER_MOTION 2 +#define WL_POINTER_BUTTON 3 +#define WL_POINTER_AXIS 4 +#define WL_POINTER_FRAME 5 +#define WL_POINTER_AXIS_SOURCE 6 +#define WL_POINTER_AXIS_STOP 7 +#define WL_POINTER_AXIS_DISCRETE 8 + +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_FRAME_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 + +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_RELEASE_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_pointer + * Sends an enter event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the enter event + * @param surface surface entered by the pointer + * @param surface_x surface-local x coordinate + * @param surface_y surface-local y coordinate + */ +static inline void +wl_pointer_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + wl_resource_post_event(resource_, WL_POINTER_ENTER, serial, surface, surface_x, surface_y); +} + +/** + * @ingroup iface_wl_pointer + * Sends an leave event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the leave event + * @param surface surface left by the pointer + */ +static inline void +wl_pointer_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface) +{ + wl_resource_post_event(resource_, WL_POINTER_LEAVE, serial, surface); +} + +/** + * @ingroup iface_wl_pointer + * Sends an motion event to the client owning the resource. + * @param resource_ The client's resource + * @param time timestamp with millisecond granularity + * @param surface_x surface-local x coordinate + * @param surface_y surface-local y coordinate + */ +static inline void +wl_pointer_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + wl_resource_post_event(resource_, WL_POINTER_MOTION, time, surface_x, surface_y); +} + +/** + * @ingroup iface_wl_pointer + * Sends an button event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the button event + * @param time timestamp with millisecond granularity + * @param button button that produced the event + * @param state physical state of the button + */ +static inline void +wl_pointer_send_button(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + wl_resource_post_event(resource_, WL_POINTER_BUTTON, serial, time, button, state); +} + +/** + * @ingroup iface_wl_pointer + * Sends an axis event to the client owning the resource. + * @param resource_ The client's resource + * @param time timestamp with millisecond granularity + * @param axis axis type + * @param value length of vector in surface-local coordinate space + */ +static inline void +wl_pointer_send_axis(struct wl_resource *resource_, uint32_t time, uint32_t axis, wl_fixed_t value) +{ + wl_resource_post_event(resource_, WL_POINTER_AXIS, time, axis, value); +} + +/** + * @ingroup iface_wl_pointer + * Sends an frame event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_pointer_send_frame(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_POINTER_FRAME); +} + +/** + * @ingroup iface_wl_pointer + * Sends an axis_source event to the client owning the resource. + * @param resource_ The client's resource + * @param axis_source source of the axis event + */ +static inline void +wl_pointer_send_axis_source(struct wl_resource *resource_, uint32_t axis_source) +{ + wl_resource_post_event(resource_, WL_POINTER_AXIS_SOURCE, axis_source); +} + +/** + * @ingroup iface_wl_pointer + * Sends an axis_stop event to the client owning the resource. + * @param resource_ The client's resource + * @param time timestamp with millisecond granularity + * @param axis the axis stopped with this event + */ +static inline void +wl_pointer_send_axis_stop(struct wl_resource *resource_, uint32_t time, uint32_t axis) +{ + wl_resource_post_event(resource_, WL_POINTER_AXIS_STOP, time, axis); +} + +/** + * @ingroup iface_wl_pointer + * Sends an axis_discrete event to the client owning the resource. + * @param resource_ The client's resource + * @param axis axis type + * @param discrete number of steps + */ +static inline void +wl_pointer_send_axis_discrete(struct wl_resource *resource_, uint32_t axis, int32_t discrete) +{ + wl_resource_post_event(resource_, WL_POINTER_AXIS_DISCRETE, axis, discrete); +} + +#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM +#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM +/** + * @ingroup iface_wl_keyboard + * keyboard mapping format + * + * This specifies the format of the keymap provided to the + * client with the wl_keyboard.keymap event. + */ +enum wl_keyboard_keymap_format { + /** + * no keymap; client must understand how to interpret the raw keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, + /** + * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, +}; +#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ + +#ifndef WL_KEYBOARD_KEY_STATE_ENUM +#define WL_KEYBOARD_KEY_STATE_ENUM +/** + * @ingroup iface_wl_keyboard + * physical key state + * + * Describes the physical state of a key that produced the key event. + */ +enum wl_keyboard_key_state { + /** + * key is not pressed + */ + WL_KEYBOARD_KEY_STATE_RELEASED = 0, + /** + * key is pressed + */ + WL_KEYBOARD_KEY_STATE_PRESSED = 1, +}; +#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ + +/** + * @ingroup iface_wl_keyboard + * @struct wl_keyboard_interface + */ +struct wl_keyboard_interface { + /** + * release the keyboard object + * + * + * @since 3 + */ + void (*release)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_KEYBOARD_KEYMAP 0 +#define WL_KEYBOARD_ENTER 1 +#define WL_KEYBOARD_LEAVE 2 +#define WL_KEYBOARD_KEY 3 +#define WL_KEYBOARD_MODIFIERS 4 +#define WL_KEYBOARD_REPEAT_INFO 5 + +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_KEY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 + +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_keyboard + * Sends an keymap event to the client owning the resource. + * @param resource_ The client's resource + * @param format keymap format + * @param fd keymap file descriptor + * @param size keymap size, in bytes + */ +static inline void +wl_keyboard_send_keymap(struct wl_resource *resource_, uint32_t format, int32_t fd, uint32_t size) +{ + wl_resource_post_event(resource_, WL_KEYBOARD_KEYMAP, format, fd, size); +} + +/** + * @ingroup iface_wl_keyboard + * Sends an enter event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the enter event + * @param surface surface gaining keyboard focus + * @param keys the currently pressed keys + */ +static inline void +wl_keyboard_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, struct wl_array *keys) +{ + wl_resource_post_event(resource_, WL_KEYBOARD_ENTER, serial, surface, keys); +} + +/** + * @ingroup iface_wl_keyboard + * Sends an leave event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the leave event + * @param surface surface that lost keyboard focus + */ +static inline void +wl_keyboard_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface) +{ + wl_resource_post_event(resource_, WL_KEYBOARD_LEAVE, serial, surface); +} + +/** + * @ingroup iface_wl_keyboard + * Sends an key event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the key event + * @param time timestamp with millisecond granularity + * @param key key that produced the event + * @param state physical state of the key + */ +static inline void +wl_keyboard_send_key(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + wl_resource_post_event(resource_, WL_KEYBOARD_KEY, serial, time, key, state); +} + +/** + * @ingroup iface_wl_keyboard + * Sends an modifiers event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the modifiers event + * @param mods_depressed depressed modifiers + * @param mods_latched latched modifiers + * @param mods_locked locked modifiers + * @param group keyboard layout + */ +static inline void +wl_keyboard_send_modifiers(struct wl_resource *resource_, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + wl_resource_post_event(resource_, WL_KEYBOARD_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group); +} + +/** + * @ingroup iface_wl_keyboard + * Sends an repeat_info event to the client owning the resource. + * @param resource_ The client's resource + * @param rate the rate of repeating keys in characters per second + * @param delay delay in milliseconds since key down until repeating starts + */ +static inline void +wl_keyboard_send_repeat_info(struct wl_resource *resource_, int32_t rate, int32_t delay) +{ + wl_resource_post_event(resource_, WL_KEYBOARD_REPEAT_INFO, rate, delay); +} + +/** + * @ingroup iface_wl_touch + * @struct wl_touch_interface + */ +struct wl_touch_interface { + /** + * release the touch object + * + * + * @since 3 + */ + void (*release)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_TOUCH_DOWN 0 +#define WL_TOUCH_UP 1 +#define WL_TOUCH_MOTION 2 +#define WL_TOUCH_FRAME 3 +#define WL_TOUCH_CANCEL 4 + +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_DOWN_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_UP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_FRAME_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_CANCEL_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_RELEASE_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_touch + * Sends an down event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the touch down event + * @param time timestamp with millisecond granularity + * @param surface surface touched + * @param id the unique ID of this touch point + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ +static inline void +wl_touch_send_down(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + wl_resource_post_event(resource_, WL_TOUCH_DOWN, serial, time, surface, id, x, y); +} + +/** + * @ingroup iface_wl_touch + * Sends an up event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial number of the touch up event + * @param time timestamp with millisecond granularity + * @param id the unique ID of this touch point + */ +static inline void +wl_touch_send_up(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t id) +{ + wl_resource_post_event(resource_, WL_TOUCH_UP, serial, time, id); +} + +/** + * @ingroup iface_wl_touch + * Sends an motion event to the client owning the resource. + * @param resource_ The client's resource + * @param time timestamp with millisecond granularity + * @param id the unique ID of this touch point + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ +static inline void +wl_touch_send_motion(struct wl_resource *resource_, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + wl_resource_post_event(resource_, WL_TOUCH_MOTION, time, id, x, y); +} + +/** + * @ingroup iface_wl_touch + * Sends an frame event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_touch_send_frame(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_TOUCH_FRAME); +} + +/** + * @ingroup iface_wl_touch + * Sends an cancel event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_touch_send_cancel(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_TOUCH_CANCEL); +} + +#ifndef WL_OUTPUT_SUBPIXEL_ENUM +#define WL_OUTPUT_SUBPIXEL_ENUM +/** + * @ingroup iface_wl_output + * subpixel geometry information + * + * This enumeration describes how the physical + * pixels on an output are laid out. + */ +enum wl_output_subpixel { + /** + * unknown geometry + */ + WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, + /** + * no geometry + */ + WL_OUTPUT_SUBPIXEL_NONE = 1, + /** + * horizontal RGB + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, + /** + * horizontal BGR + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, + /** + * vertical RGB + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, + /** + * vertical BGR + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, +}; +#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ + +#ifndef WL_OUTPUT_TRANSFORM_ENUM +#define WL_OUTPUT_TRANSFORM_ENUM +/** + * @ingroup iface_wl_output + * transform from framebuffer to output + * + * This describes the transform that a compositor will apply to a + * surface to compensate for the rotation or mirroring of an + * output device. + * + * The flipped values correspond to an initial flip around a + * vertical axis followed by rotation. + * + * The purpose is mainly to allow clients to render accordingly and + * tell the compositor, so that for fullscreen surfaces, the + * compositor will still be able to scan out directly from client + * surfaces. + */ +enum wl_output_transform { + /** + * no transform + */ + WL_OUTPUT_TRANSFORM_NORMAL = 0, + /** + * 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_90 = 1, + /** + * 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_180 = 2, + /** + * 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_270 = 3, + /** + * 180 degree flip around a vertical axis + */ + WL_OUTPUT_TRANSFORM_FLIPPED = 4, + /** + * flip and rotate 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, + /** + * flip and rotate 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, + /** + * flip and rotate 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, +}; +#endif /* WL_OUTPUT_TRANSFORM_ENUM */ + +#ifndef WL_OUTPUT_MODE_ENUM +#define WL_OUTPUT_MODE_ENUM +/** + * @ingroup iface_wl_output + * mode information + * + * These flags describe properties of an output mode. + * They are used in the flags bitfield of the mode event. + */ +enum wl_output_mode { + /** + * indicates this is the current mode + */ + WL_OUTPUT_MODE_CURRENT = 0x1, + /** + * indicates this is the preferred mode + */ + WL_OUTPUT_MODE_PREFERRED = 0x2, +}; +#endif /* WL_OUTPUT_MODE_ENUM */ + +/** + * @ingroup iface_wl_output + * @struct wl_output_interface + */ +struct wl_output_interface { + /** + * release the output object + * + * Using this request a client can tell the server that it is not + * going to use the output object anymore. + * @since 3 + */ + void (*release)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define WL_OUTPUT_GEOMETRY 0 +#define WL_OUTPUT_MODE 1 +#define WL_OUTPUT_DONE 2 +#define WL_OUTPUT_SCALE 3 + +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_DONE_SINCE_VERSION 2 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_SCALE_SINCE_VERSION 2 + +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_RELEASE_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_output + * Sends an geometry event to the client owning the resource. + * @param resource_ The client's resource + * @param x x position within the global compositor space + * @param y y position within the global compositor space + * @param physical_width width in millimeters of the output + * @param physical_height height in millimeters of the output + * @param subpixel subpixel orientation of the output + * @param make textual description of the manufacturer + * @param model textual description of the model + * @param transform transform that maps framebuffer to output + */ +static inline void +wl_output_send_geometry(struct wl_resource *resource_, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform) +{ + wl_resource_post_event(resource_, WL_OUTPUT_GEOMETRY, x, y, physical_width, physical_height, subpixel, make, model, transform); +} + +/** + * @ingroup iface_wl_output + * Sends an mode event to the client owning the resource. + * @param resource_ The client's resource + * @param flags bitfield of mode flags + * @param width width of the mode in hardware units + * @param height height of the mode in hardware units + * @param refresh vertical refresh rate in mHz + */ +static inline void +wl_output_send_mode(struct wl_resource *resource_, uint32_t flags, int32_t width, int32_t height, int32_t refresh) +{ + wl_resource_post_event(resource_, WL_OUTPUT_MODE, flags, width, height, refresh); +} + +/** + * @ingroup iface_wl_output + * Sends an done event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wl_output_send_done(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WL_OUTPUT_DONE); +} + +/** + * @ingroup iface_wl_output + * Sends an scale event to the client owning the resource. + * @param resource_ The client's resource + * @param factor scaling factor of output + */ +static inline void +wl_output_send_scale(struct wl_resource *resource_, int32_t factor) +{ + wl_resource_post_event(resource_, WL_OUTPUT_SCALE, factor); +} + +/** + * @ingroup iface_wl_region + * @struct wl_region_interface + */ +struct wl_region_interface { + /** + * destroy region + * + * Destroy the region. This will invalidate the object ID. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * add rectangle to region + * + * Add the specified rectangle to the region. + * @param x region-local x coordinate + * @param y region-local y coordinate + * @param width rectangle width + * @param height rectangle height + */ + void (*add)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * subtract rectangle from region + * + * Subtract the specified rectangle from the region. + * @param x region-local x coordinate + * @param y region-local y coordinate + * @param width rectangle width + * @param height rectangle height + */ + void (*subtract)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); +}; + + +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_ADD_SINCE_VERSION 1 +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_SUBTRACT_SINCE_VERSION 1 + +#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM +#define WL_SUBCOMPOSITOR_ERROR_ENUM +enum wl_subcompositor_error { + /** + * the to-be sub-surface is invalid + */ + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ + +/** + * @ingroup iface_wl_subcompositor + * @struct wl_subcompositor_interface + */ +struct wl_subcompositor_interface { + /** + * unbind from the subcompositor interface + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other objects, + * wl_subsurface objects included. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * give a surface the role sub-surface + * + * Create a sub-surface interface for the given surface, and + * associate it with the given parent surface. This turns a plain + * wl_surface into a sub-surface. + * + * The to-be sub-surface must not already have another role, and it + * must not have an existing wl_subsurface object. Otherwise a + * protocol error is raised. + * @param id the new sub-surface object ID + * @param surface the surface to be turned into a sub-surface + * @param parent the parent surface + */ + void (*get_subsurface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface, + struct wl_resource *parent); +}; + + +/** + * @ingroup iface_wl_subcompositor + */ +#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subcompositor + */ +#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 + +#ifndef WL_SUBSURFACE_ERROR_ENUM +#define WL_SUBSURFACE_ERROR_ENUM +enum wl_subsurface_error { + /** + * wl_surface is not a sibling or the parent + */ + WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBSURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_subsurface + * @struct wl_subsurface_interface + */ +struct wl_subsurface_interface { + /** + * remove sub-surface interface + * + * The sub-surface interface is removed from the wl_surface + * object that was turned into a sub-surface with a + * wl_subcompositor.get_subsurface request. The wl_surface's + * association to the parent is deleted, and the wl_surface loses + * its role as a sub-surface. The wl_surface is unmapped. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * reposition the sub-surface + * + * This schedules a sub-surface position change. The sub-surface + * will be moved so that its origin (top left corner pixel) will be + * at the location x, y of the parent surface coordinate system. + * The coordinates are not restricted to the parent surface area. + * Negative values are allowed. + * + * The scheduled coordinates will take effect whenever the state of + * the parent surface is applied. When this happens depends on + * whether the parent surface is in synchronized mode or not. See + * wl_subsurface.set_sync and wl_subsurface.set_desync for details. + * + * If more than one set_position request is invoked by the client + * before the commit of the parent surface, the position of a new + * request always replaces the scheduled position from any previous + * request. + * + * The initial position is 0, 0. + * @param x x coordinate in the parent surface + * @param y y coordinate in the parent surface + */ + void (*set_position)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y); + /** + * restack the sub-surface + * + * This sub-surface is taken from the stack, and put back just + * above the reference surface, changing the z-order of the + * sub-surfaces. The reference surface must be one of the sibling + * surfaces, or the parent surface. Using any other surface, + * including this sub-surface, will cause a protocol error. + * + * The z-order is double-buffered. Requests are handled in order + * and applied immediately to a pending state. The final pending + * state is copied to the active state the next time the state of + * the parent surface is applied. When this happens depends on + * whether the parent surface is in synchronized mode or not. See + * wl_subsurface.set_sync and wl_subsurface.set_desync for details. + * + * A new sub-surface is initially added as the top-most in the + * stack of its siblings and parent. + * @param sibling the reference surface + */ + void (*place_above)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *sibling); + /** + * restack the sub-surface + * + * The sub-surface is placed just below the reference surface. + * See wl_subsurface.place_above. + * @param sibling the reference surface + */ + void (*place_below)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *sibling); + /** + * set sub-surface to synchronized mode + * + * Change the commit behaviour of the sub-surface to synchronized + * mode, also described as the parent dependent mode. + * + * In synchronized mode, wl_surface.commit on a sub-surface will + * accumulate the committed state in a cache, but the state will + * not be applied and hence will not change the compositor output. + * The cached state is applied to the sub-surface immediately after + * the parent surface's state is applied. This ensures atomic + * updates of the parent and all its synchronized sub-surfaces. + * Applying the cached state will invalidate the cache, so further + * parent surface commits do not (re-)apply old state. + * + * See wl_subsurface for the recursive effect of this mode. + */ + void (*set_sync)(struct wl_client *client, + struct wl_resource *resource); + /** + * set sub-surface to desynchronized mode + * + * Change the commit behaviour of the sub-surface to + * desynchronized mode, also described as independent or freely + * running mode. + * + * In desynchronized mode, wl_surface.commit on a sub-surface will + * apply the pending state directly, without caching, as happens + * normally with a wl_surface. Calling wl_surface.commit on the + * parent surface has no effect on the sub-surface's wl_surface + * state. This mode allows a sub-surface to be updated on its own. + * + * If cached state exists when wl_surface.commit is called in + * desynchronized mode, the pending state is added to the cached + * state, and applied as a whole. This invalidates the cache. + * + * Note: even if a sub-surface is set to desynchronized, a parent + * sub-surface may override it to behave as synchronized. For + * details, see wl_subsurface. + * + * If a surface's parent surface behaves as desynchronized, then + * the cached state is applied on set_desync. + */ + void (*set_desync)(struct wl_client *client, + struct wl_resource *resource); +}; + + +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/example.xml b/tests/data/example.xml new file mode 100644 index 00000000..6c6d078a --- /dev/null +++ b/tests/data/example.xml @@ -0,0 +1,2693 @@ + + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2011 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + + + + The core global object. This is a special singleton object. It + is used for internal Wayland protocol features. + + + + + The sync request asks the server to emit the 'done' event + on the returned wl_callback object. Since requests are + handled in-order and events are delivered in-order, this can + be used as a barrier to ensure all previous requests and the + resulting events have been handled. + + The object returned by this request will be destroyed by the + compositor after the callback is fired and as such the client must not + attempt to use it after that point. + + The callback_data passed in the callback is the event serial. + + + + + + + This request creates a registry object that allows the client + to list and bind the global objects available from the + compositor. + + + + + + + The error event is sent out when a fatal (non-recoverable) + error has occurred. The object_id argument is the object + where the error occurred, most often in response to a request + to that object. The code identifies the error and is defined + by the object interface. As such, each interface defines its + own set of error codes. The message is a brief description + of the error, for (debugging) convenience. + + + + + + + + + These errors are global and can be emitted in response to any + server request. + + + + + + + + + This event is used internally by the object ID management + logic. When a client deletes an object, the server will send + this event to acknowledge that it has seen the delete request. + When the client receives this event, it will know that it can + safely reuse the object ID. + + + + + + + + The global registry object. The server has a number of global + objects that are available to all clients. These objects + typically represent an actual object in the server (for example, + an input device) or they are singleton objects that provide + extension functionality. + + When a client creates a registry object, the registry object + will emit a global event for each global currently in the + registry. Globals come and go as a result of device or + monitor hotplugs, reconfiguration or other events, and the + registry will send out global and global_remove events to + keep the client up to date with the changes. To mark the end + of the initial burst of events, the client can use the + wl_display.sync request immediately after calling + wl_display.get_registry. + + A client can bind to a global object by using the bind + request. This creates a client-side handle that lets the object + emit events to the client and lets the client invoke requests on + the object. + + + + + Binds a new, client-created object to the server using the + specified name as the identifier. + + + + + + + + Notify the client of global objects. + + The event notifies the client that a global object with + the given name is now available, and it implements the + given version of the given interface. + + + + + + + + + Notify the client of removed global objects. + + This event notifies the client that the global identified + by name is no longer available. If the client bound to + the global using the bind request, the client should now + destroy that object. + + The object remains valid and requests to the object will be + ignored until the client destroys it, to avoid races between + the global going away and a client sending a request to it. + + + + + + + + Clients can handle the 'done' event to get notified when + the related request is done. + + + + + Notify the client when the related request is done. + + + + + + + + A compositor. This object is a singleton global. The + compositor is in charge of combining the contents of multiple + surfaces into one displayable output. + + + + + Ask the compositor to create a new surface. + + + + + + + Ask the compositor to create a new region. + + + + + + + + The wl_shm_pool object encapsulates a piece of memory shared + between the compositor and client. Through the wl_shm_pool + object, the client can allocate shared memory wl_buffer objects. + All objects created through the same pool share the same + underlying mapped memory. Reusing the mapped memory avoids the + setup/teardown overhead and is useful when interactively resizing + a surface or for many small buffers. + + + + + Create a wl_buffer object from the pool. + + The buffer is created offset bytes into the pool and has + width and height as specified. The stride argument specifies + the number of bytes from the beginning of one row to the beginning + of the next. The format is the pixel format of the buffer and + must be one of those advertised through the wl_shm.format event. + + A buffer will keep a reference to the pool it was created from + so it is valid to destroy the pool immediately after creating + a buffer from it. + + + + + + + + + + + + + Destroy the shared memory pool. + + The mmapped memory will be released when all + buffers that have been created from this pool + are gone. + + + + + + This request will cause the server to remap the backing memory + for the pool from the file descriptor passed when the pool was + created, but using the new size. This request can only be + used to make the pool bigger. + + + + + + + + + A global singleton object that provides support for shared + memory. + + Clients can create wl_shm_pool objects using the create_pool + request. + + At connection setup time, the wl_shm object emits one or more + format events to inform clients about the valid pixel formats + that can be used for buffers. + + + + + These errors can be emitted in response to wl_shm requests. + + + + + + + + + This describes the memory layout of an individual pixel. + + All renderers should support argb8888 and xrgb8888 but any other + formats are optional and may not be supported by the particular + renderer in use. + + The drm format codes match the macros defined in drm_fourcc.h. + The formats actually supported by the compositor will be + reported by the format event. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create a new wl_shm_pool object. + + The pool can be used to create shared memory based buffer + objects. The server will mmap size bytes of the passed file + descriptor, to use as backing memory for the pool. + + + + + + + + + + Informs the client about a valid pixel format that + can be used for buffers. Known formats include + argb8888 and xrgb8888. + + + + + + + + A buffer provides the content for a wl_surface. Buffers are + created through factory interfaces such as wl_drm, wl_shm or + similar. It has a width and a height and can be attached to a + wl_surface, but the mechanism by which a client provides and + updates the contents is defined by the buffer factory interface. + + + + + Destroy a buffer. If and how you need to release the backing + storage is defined by the buffer factory interface. + + For possible side-effects to a surface, see wl_surface.attach. + + + + + + Sent when this wl_buffer is no longer used by the compositor. + The client is now free to reuse or destroy this buffer and its + backing storage. + + If a client receives a release event before the frame callback + requested in the same wl_surface.commit that attaches this + wl_buffer to a surface, then the client is immediately free to + reuse the buffer and its backing storage, and does not need a + second buffer for the next surface content update. Typically + this is possible, when the compositor maintains a copy of the + wl_surface contents, e.g. as a GL texture. This is an important + optimization for GL(ES) compositors with wl_shm clients. + + + + + + + A wl_data_offer represents a piece of data offered for transfer + by another client (the source client). It is used by the + copy-and-paste and drag-and-drop mechanisms. The offer + describes the different mime types that the data can be + converted to and provides the mechanism for transferring the + data directly from the source client. + + + + + + + + + + + + Indicate that the client can accept the given mime type, or + NULL for not accepted. + + For objects of version 2 or older, this request is used by the + client to give feedback whether the client can receive the given + mime type, or NULL if none is accepted; the feedback does not + determine whether the drag-and-drop operation succeeds or not. + + For objects of version 3 or newer, this request determines the + final result of the drag-and-drop operation. If the end result + is that no mime types were accepted, the drag-and-drop operation + will be cancelled and the corresponding drag source will receive + wl_data_source.cancelled. Clients may still use this event in + conjunction with wl_data_source.action for feedback. + + + + + + + + + To transfer the offered data, the client issues this request + and indicates the mime type it wants to receive. The transfer + happens through the passed file descriptor (typically created + with the pipe system call). The source client writes the data + in the mime type representation requested and then closes the + file descriptor. + + The receiving client reads from the read end of the pipe until + EOF and then closes its end, at which point the transfer is + complete. + + This request may happen multiple times for different mime types, + both before and after wl_data_device.drop. Drag-and-drop destination + clients may preemptively fetch data or examine it more closely to + determine acceptance. + + + + + + + + Destroy the data offer. + + + + + + Sent immediately after creating the wl_data_offer object. One + event per offered mime type. + + + + + + + + + + Notifies the compositor that the drag destination successfully + finished the drag-and-drop operation. + + Upon receiving this request, the compositor will emit + wl_data_source.dnd_finished on the drag source client. + + It is a client error to perform other requests than + wl_data_offer.destroy after this one. It is also an error to perform + this request after a NULL mime type has been set in + wl_data_offer.accept or no action was received through + wl_data_offer.action. + + + + + + Sets the actions that the destination side client supports for + this operation. This request may trigger the emission of + wl_data_source.action and wl_data_offer.action events if the compositor + needs to change the selected action. + + This request can be called multiple times throughout the + drag-and-drop operation, typically in response to wl_data_device.enter + or wl_data_device.motion events. + + This request determines the final result of the drag-and-drop + operation. If the end result is that no action is accepted, + the drag source will receive wl_drag_source.cancelled. + + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, and the preferred_action + argument must only contain one of those values set, otherwise it + will result in a protocol error. + + While managing an "ask" action, the destination drag-and-drop client + may perform further wl_data_offer.receive requests, and is expected + to perform one last wl_data_offer.set_actions request with a preferred + action other than "ask" (and optionally wl_data_offer.accept) before + requesting wl_data_offer.finish, in order to convey the action selected + by the user. If the preferred action is not in the + wl_data_offer.source_actions mask, an error will be raised. + + If the "ask" action is dismissed (e.g. user cancellation), the client + is expected to perform wl_data_offer.destroy right away. + + This request can only be made on drag-and-drop offers, a protocol error + will be raised otherwise. + + + + + + + + This event indicates the actions offered by the data source. It + will be sent right after wl_data_device.enter, or anytime the source + side changes its offered actions through wl_data_source.set_actions. + + + + + + + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. + + This event can be emitted multiple times during the drag-and-drop + operation in response to destination side action changes through + wl_data_offer.set_actions. + + This event will no longer be emitted after wl_data_device.drop + happened on the drag-and-drop destination, the client must + honor the last action received, or the last preferred one set + through wl_data_offer.set_actions when handling an "ask" action. + + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. + + The most recent action received is always the valid one. Prior to + receiving wl_data_device.drop, the chosen action may change (e.g. + due to keyboard modifiers being pressed). At the time of receiving + wl_data_device.drop the drag-and-drop destination must honor the + last action received. + + Action changes may still happen after wl_data_device.drop, + especially on "ask" actions, where the drag-and-drop destination + may choose another action afterwards. Action changes happening + at this stage are always the result of inter-client negotiation, the + compositor shall no longer be able to induce a different action. + + Upon "ask" actions, it is expected that the drag-and-drop destination + may potentially choose a different action and/or mime type, + based on wl_data_offer.source_actions and finally chosen by the + user (e.g. popping up a menu with the available options). The + final wl_data_offer.set_actions and wl_data_offer.accept requests + must happen before the call to wl_data_offer.finish. + + + + + + + + The wl_data_source object is the source side of a wl_data_offer. + It is created by the source client in a data transfer and + provides a way to describe the offered data and a way to respond + to requests to transfer the data. + + + + + + + + + + This request adds a mime type to the set of mime types + advertised to targets. Can be called several times to offer + multiple types. + + + + + + + Destroy the data source. + + + + + + Sent when a target accepts pointer_focus or motion events. If + a target does not accept any of the offered types, type is NULL. + + Used for feedback during drag-and-drop. + + + + + + + + Request for data from the client. Send the data as the + specified mime type over the passed file descriptor, then + close it. + + + + + + + + + This data source is no longer valid. There are several reasons why + this could happen: + + - The data source has been replaced by another data source. + - The drag-and-drop operation was performed, but the drop destination + did not accept any of the mime types offered through + wl_data_source.target. + - The drag-and-drop operation was performed, but the drop destination + did not select any of the actions present in the mask offered through + wl_data_source.action. + - The drag-and-drop operation was performed but didn't happen over a + surface. + - The compositor cancelled the drag-and-drop operation (e.g. compositor + dependent timeouts to avoid stale drag-and-drop transfers). + + The client should clean up and destroy this data source. + + For objects of version 2 or older, wl_data_source.cancelled will + only be emitted if the data source was replaced by another data + source. + + + + + + + + Sets the actions that the source side client supports for this + operation. This request may trigger wl_data_source.action and + wl_data_offer.action events if the compositor needs to change the + selected action. + + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, otherwise it will result + in a protocol error. + + This request must be made once only, and can only be made on sources + used in drag-and-drop, so it must be performed before + wl_data_device.start_drag. Attempting to use the source other than + for drag-and-drop will raise a protocol error. + + + + + + + The user performed the drop action. This event does not indicate + acceptance, wl_data_source.cancelled may still be emitted afterwards + if the drop destination does not accept any mime type. + + However, this event might however not be received if the compositor + cancelled the drag-and-drop operation before this event could happen. + + Note that the data_source may still be used in the future and should + not be destroyed here. + + + + + + The drop destination finished interoperating with this data + source, so the client is now free to destroy this data source and + free all associated data. + + If the action used to perform the operation was "move", the + source can now delete the transferred data. + + + + + + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. + + This event can be emitted multiple times during the drag-and-drop + operation, mainly in response to destination side changes through + wl_data_offer.set_actions, and as the data device enters/leaves + surfaces. + + It is only possible to receive this event after + wl_data_source.dnd_drop_performed if the drag-and-drop operation + ended in an "ask" action, in which case the final wl_data_source.action + event will happen immediately before wl_data_source.dnd_finished. + + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. + + The most recent action received is always the valid one. The chosen + action may change alongside negotiation (e.g. an "ask" action can turn + into a "move" operation), so the effects of the final action must + always be applied in wl_data_offer.dnd_finished. + + Clients can trigger cursor surface changes from this point, so + they reflect the current action. + + + + + + + + There is one wl_data_device per seat which can be obtained + from the global wl_data_device_manager singleton. + + A wl_data_device provides access to inter-client data transfer + mechanisms such as copy-and-paste and drag-and-drop. + + + + + + + + + This request asks the compositor to start a drag-and-drop + operation on behalf of the client. + + The source argument is the data source that provides the data + for the eventual data transfer. If source is NULL, enter, leave + and motion events are sent only to the client that initiated the + drag and the client is expected to handle the data passing + internally. + + The origin surface is the surface where the drag originates and + the client must have an active implicit grab that matches the + serial. + + The icon surface is an optional (can be NULL) surface that + provides an icon to be moved around with the cursor. Initially, + the top-left corner of the icon surface is placed at the cursor + hotspot, but subsequent wl_surface.attach request can move the + relative position. Attach requests must be confirmed with + wl_surface.commit as usual. The icon surface is given the role of + a drag-and-drop icon. If the icon surface already has another role, + it raises a protocol error. + + The current and pending input regions of the icon wl_surface are + cleared, and wl_surface.set_input_region is ignored until the + wl_surface is no longer used as the icon surface. When the use + as an icon ends, the current and pending input regions become + undefined, and the wl_surface is unmapped. + + + + + + + + + + This request asks the compositor to set the selection + to the data from the source on behalf of the client. + + To unset the selection, set the source to NULL. + + + + + + + + The data_offer event introduces a new wl_data_offer object, + which will subsequently be used in either the + data_device.enter event (for drag-and-drop) or the + data_device.selection event (for selections). Immediately + following the data_device_data_offer event, the new data_offer + object will send out data_offer.offer events to describe the + mime types it offers. + + + + + + + + This event is sent when an active drag-and-drop pointer enters + a surface owned by the client. The position of the pointer at + enter time is provided by the x and y arguments, in surface-local + coordinates. + + + + + + + + + + + + This event is sent when the drag-and-drop pointer leaves the + surface and the session ends. The client must destroy the + wl_data_offer introduced at enter time at this point. + + + + + + This event is sent when the drag-and-drop pointer moves within + the currently focused surface. The new position of the pointer + is provided by the x and y arguments, in surface-local + coordinates. + + + + + + + + + The event is sent when a drag-and-drop operation is ended + because the implicit grab is removed. + + The drag-and-drop destination is expected to honor the last action + received through wl_data_offer.action, if the resulting action is + "copy" or "move", the destination can still perform + wl_data_offer.receive requests, and is expected to end all + transfers with a wl_data_offer.finish request. + + If the resulting action is "ask", the action will not be considered + final. The drag-and-drop destination is expected to perform one last + wl_data_offer.set_actions request, or wl_data_offer.destroy in order + to cancel the operation. + + + + + + The selection event is sent out to notify the client of a new + wl_data_offer for the selection for this device. The + data_device.data_offer and the data_offer.offer events are + sent out immediately before this event to introduce the data + offer object. The selection event is sent to a client + immediately before receiving keyboard focus and when a new + selection is set while the client has keyboard focus. The + data_offer is valid until a new data_offer or NULL is received + or until the client loses keyboard focus. The client must + destroy the previous selection data_offer, if any, upon receiving + this event. + + + + + + + + + This request destroys the data device. + + + + + + + The wl_data_device_manager is a singleton global object that + provides access to inter-client data transfer mechanisms such as + copy-and-paste and drag-and-drop. These mechanisms are tied to + a wl_seat and this interface lets a client get a wl_data_device + corresponding to a wl_seat. + + Depending on the version bound, the objects created from the bound + wl_data_device_manager object will have different requirements for + functioning properly. See wl_data_source.set_actions, + wl_data_offer.accept and wl_data_offer.finish for details. + + + + + Create a new data source. + + + + + + + Create a new data device for a given seat. + + + + + + + + + + This is a bitmask of the available/preferred actions in a + drag-and-drop operation. + + In the compositor, the selected action is a result of matching the + actions offered by the source and destination sides. "action" events + with a "none" action will be sent to both source and destination if + there is no match. All further checks will effectively happen on + (source actions ∩ destination actions). + + In addition, compositors may also pick different actions in + reaction to key modifiers being pressed. One common design that + is used in major toolkits (and the behavior recommended for + compositors) is: + + - If no modifiers are pressed, the first match (in bit order) + will be used. + - Pressing Shift selects "move", if enabled in the mask. + - Pressing Control selects "copy", if enabled in the mask. + + Behavior beyond that is considered implementation-dependent. + Compositors may for example bind other modifiers (like Alt/Meta) + or drags initiated with other buttons than BTN_LEFT to specific + actions (e.g. "ask"). + + + + + + + + + + + This interface is implemented by servers that provide + desktop-style user interfaces. + + It allows clients to associate a wl_shell_surface with + a basic surface. + + + + + + + + + Create a shell surface for an existing surface. This gives + the wl_surface the role of a shell surface. If the wl_surface + already has another role, it raises a protocol error. + + Only one shell surface can be associated with a given surface. + + + + + + + + + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style user interface. + + It provides requests to treat surfaces like toplevel, fullscreen + or popup windows, move, resize or maximize them, associate + metadata like title and class, etc. + + On the server side the object is automatically destroyed when + the related wl_surface is destroyed. On the client side, + wl_shell_surface_destroy() must be called before destroying + the wl_surface object. + + + + + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. + + + + + + + Start a pointer-driven move of the surface. + + This request must be used in response to a button press event. + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized). + + + + + + + + These values are used to indicate which edge of a surface + is being dragged in a resize operation. The server may + use this information to adapt its behavior, e.g. choose + an appropriate cursor image. + + + + + + + + + + + + + + + Start a pointer-driven resizing of the surface. + + This request must be used in response to a button press event. + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). + + + + + + + + + Map the surface as a toplevel surface. + + A toplevel surface is not fullscreen, maximized or transient. + + + + + + These flags specify details of the expected behaviour + of transient surfaces. Used in the set_transient request. + + + + + + + Map the surface relative to an existing surface. + + The x and y arguments specify the location of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface-local coordinates. + + The flags argument controls details of the transient behaviour. + + + + + + + + + + + Hints to indicate to the compositor how to deal with a conflict + between the dimensions of the surface and the dimensions of the + output. The compositor is free to ignore this parameter. + + + + + + + + + + Map the surface as a fullscreen surface. + + If an output parameter is given then the surface will be made + fullscreen on that output. If the client does not specify the + output then the compositor will apply its policy - usually + choosing the output on which the surface has the biggest surface + area. + + The client may specify a method to resolve a size conflict + between the output size and the surface size - this is provided + through the method parameter. + + The framerate parameter is used only when the method is set + to "driver", to indicate the preferred framerate. A value of 0 + indicates that the client does not care about framerate. The + framerate is specified in mHz, that is framerate of 60000 is 60Hz. + + A method of "scale" or "driver" implies a scaling operation of + the surface, either via a direct scaling operation or a change of + the output mode. This will override any kind of output scaling, so + that mapping a surface with a buffer size equal to the mode can + fill the screen independent of buffer_scale. + + A method of "fill" means we don't scale up the buffer, however + any output scale is applied. This means that you may run into + an edge case where the application maps a buffer with the same + size of the output mode but buffer_scale 1 (thus making a + surface larger than the output). In this case it is allowed to + downscale the results to fit the screen. + + The compositor must reply to this request with a configure event + with the dimensions for the output on which the surface will + be made fullscreen. + + + + + + + + + Map the surface as a popup. + + A popup surface is a transient surface with an added pointer + grab. + + An existing implicit grab will be changed to owner-events mode, + and the popup grab will continue after the implicit grab ends + (i.e. releasing the mouse button does not cause the popup to + be unmapped). + + The popup grab continues until the window is destroyed or a + mouse button is pressed in any other client's window. A click + in any of the client's surfaces is reported as normal, however, + clicks in other clients' surfaces will be discarded and trigger + the callback. + + The x and y arguments specify the location of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface-local coordinates. + + + + + + + + + + + + + Map the surface as a maximized surface. + + If an output parameter is given then the surface will be + maximized on that output. If the client does not specify the + output then the compositor will apply its policy - usually + choosing the output on which the surface has the biggest surface + area. + + The compositor will reply with a configure event telling + the expected new surface size. The operation is completed + on the next buffer attach to this surface. + + A maximized surface typically fills the entire output it is + bound to, except for desktop elements such as panels. This is + the main difference between a maximized shell surface and a + fullscreen shell surface. + + The details depend on the compositor implementation. + + + + + + + Set a short title for the surface. + + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. + + The string must be encoded in UTF-8. + + + + + + + Set a class for the surface. + + The surface class identifies the general class of applications + to which the surface belongs. A common convention is to use the + file name (or the full path if it is a non-standard location) of + the application's .desktop file as the class. + + + + + + + Ping a client to check if it is receiving events and sending + requests. A client is expected to reply with a pong request. + + + + + + + The configure event asks the client to resize its surface. + + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). + + The edges parameter provides a hint about how the surface + was resized. The client may use this information to decide + how to adjust its content to the new size (e.g. a scrolling + area might adjust its content position to leave the viewable + content unmoved). + + The client is free to dismiss all but the last configure + event it received. + + The width and height arguments specify the size of the window + in surface-local coordinates. + + + + + + + + + + The popup_done event is sent out when a popup grab is broken, + that is, when the user clicks a surface that doesn't belong + to the client owning the popup surface. + + + + + + + A surface is a rectangular area that is displayed on the screen. + It has a location, size and pixel contents. + + The size of a surface (and relative positions on it) is described + in surface-local coordinates, which may differ from the buffer + coordinates of the pixel content, in case a buffer_transform + or a buffer_scale is used. + + A surface without a "role" is fairly useless: a compositor does + not know where, when or how to present it. The role is the + purpose of a wl_surface. Examples of roles are a cursor for a + pointer (as set by wl_pointer.set_cursor), a drag icon + (wl_data_device.start_drag), a sub-surface + (wl_subcompositor.get_subsurface), and a window as defined by a + shell protocol (e.g. wl_shell.get_shell_surface). + + A surface can have only one role at a time. Initially a + wl_surface does not have a role. Once a wl_surface is given a + role, it is set permanently for the whole lifetime of the + wl_surface object. Giving the current role again is allowed, + unless explicitly forbidden by the relevant interface + specification. + + Surface roles are given by requests in other interfaces such as + wl_pointer.set_cursor. The request should explicitly mention + that this request gives a role to a wl_surface. Often, this + request also creates a new protocol object that represents the + role and adds additional functionality to wl_surface. When a + client wants to destroy a wl_surface, they must destroy this 'role + object' before the wl_surface. + + Destroying the role object does not remove the role from the + wl_surface, but it may stop the wl_surface from "playing the role". + For instance, if a wl_subsurface object is destroyed, the wl_surface + it was created for will be unmapped and forget its position and + z-order. It is allowed to create a wl_subsurface for the same + wl_surface again, but it is not allowed to use the wl_surface as + a cursor (cursor is a different role than sub-surface, and role + switching is not allowed). + + + + + These errors can be emitted in response to wl_surface requests. + + + + + + + + Deletes the surface and invalidates its object ID. + + + + + + Set a buffer as the content of this surface. + + The new size of the surface is calculated based on the buffer + size transformed by the inverse buffer_transform and the + inverse buffer_scale. This means that the supplied buffer + must be an integer multiple of the buffer_scale. + + The x and y arguments specify the location of the new pending + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface-local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. + + Surface contents are double-buffered state, see wl_surface.commit. + + The initial surface contents are void; there is no content. + wl_surface.attach assigns the given wl_buffer as the pending + wl_buffer. wl_surface.commit makes the pending wl_buffer the new + surface contents, and the size of the surface becomes the size + calculated from the wl_buffer, as described above. After commit, + there is no pending buffer until the next attach. + + Committing a pending wl_buffer allows the compositor to read the + pixels in the wl_buffer. The compositor may access the pixels at + any time after the wl_surface.commit request. When the compositor + will not access the pixels anymore, it will send the + wl_buffer.release event. Only after receiving wl_buffer.release, + the client may reuse the wl_buffer. A wl_buffer that has been + attached and then replaced by another attach instead of committed + will not receive a release event, and is not used by the + compositor. + + Destroying the wl_buffer after wl_buffer.release does not change + the surface contents. However, if the client destroys the + wl_buffer before receiving the wl_buffer.release event, the surface + contents become undefined immediately. + + If wl_surface.attach is sent with a NULL wl_buffer, the + following wl_surface.commit will remove the surface content. + + + + + + + + + + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. + + Damage is double-buffered state, see wl_surface.commit. + + The damage rectangle is specified in surface-local coordinates, + where x and y specify the upper left corner of the damage rectangle. + + The initial value for pending damage is empty: no damage. + wl_surface.damage adds pending damage: the new pending damage + is the union of old pending damage and the given rectangle. + + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. + + Alternatively, damage can be posted with wl_surface.damage_buffer + which uses buffer coordinates instead of surface coordinates, + and is probably the preferred and intuitive way of doing this. + + + + + + + + + + + Request a notification when it is a good time to start drawing a new + frame, by creating a frame callback. This is useful for throttling + redrawing operations, and driving animations. + + When a client is animating on a wl_surface, it can use the 'frame' + request to get notified when it is a good time to draw and commit the + next frame of animation. If the client commits an update earlier than + that, it is likely that some updates will not make it to the display, + and the client is wasting resources by drawing too often. + + The frame request will take effect on the next wl_surface.commit. + The notification will only be posted for one frame unless + requested again. For a wl_surface, the notifications are posted in + the order the frame requests were committed. + + The server must send the notifications so that a client + will not send excessive updates, while still allowing + the highest possible update rate for clients that wait for the reply + before drawing again. The server should give some time for the client + to draw and commit after sending the frame callback events to let it + hit the next output refresh. + + A server should avoid signaling the frame callbacks if the + surface is not visible in any way, e.g. the surface is off-screen, + or completely obscured by other opaque surfaces. + + The object returned by this request will be destroyed by the + compositor after the callback is fired and as such the client must not + attempt to use it after that point. + + The callback_data passed in the callback is the current time, in + milliseconds, with an undefined base. + + + + + + + + This request sets the region of the surface that contains + opaque content. + + The opaque region is an optimization hint for the compositor + that lets it optimize the redrawing of content behind opaque + regions. Setting an opaque region is not required for correct + behaviour, but marking transparent content as opaque will result + in repaint artifacts. + + The opaque region is specified in surface-local coordinates. + + The compositor ignores the parts of the opaque region that fall + outside of the surface. + + Opaque region is double-buffered state, see wl_surface.commit. + + wl_surface.set_opaque_region changes the pending opaque region. + wl_surface.commit copies the pending region to the current region. + Otherwise, the pending and current regions are never changed. + + The initial value for an opaque region is empty. Setting the pending + opaque region has copy semantics, and the wl_region object can be + destroyed immediately. A NULL wl_region causes the pending opaque + region to be set to empty. + + + + + + + + This request sets the region of the surface that can receive + pointer and touch events. + + Input events happening outside of this region will try the next + surface in the server surface stack. The compositor ignores the + parts of the input region that fall outside of the surface. + + The input region is specified in surface-local coordinates. + + Input region is double-buffered state, see wl_surface.commit. + + wl_surface.set_input_region changes the pending input region. + wl_surface.commit copies the pending region to the current region. + Otherwise the pending and current regions are never changed, + except cursor and icon surfaces are special cases, see + wl_pointer.set_cursor and wl_data_device.start_drag. + + The initial value for an input region is infinite. That means the + whole surface will accept input. Setting the pending input region + has copy semantics, and the wl_region object can be destroyed + immediately. A NULL wl_region causes the input region to be set + to infinite. + + + + + + + + Surface state (input, opaque, and damage regions, attached buffers, + etc.) is double-buffered. Protocol requests modify the pending state, + as opposed to the current state in use by the compositor. A commit + request atomically applies all pending state, replacing the current + state. After commit, the new pending state is as documented for each + related request. + + On commit, a pending wl_buffer is applied first, and all other state + second. This means that all coordinates in double-buffered state are + relative to the new wl_buffer coming into use, except for + wl_surface.attach itself. If there is no pending wl_buffer, the + coordinates are relative to the current surface contents. + + All requests that need a commit to become effective are documented + to affect double-buffered state. + + Other interfaces may add further double-buffered surface state. + + + + + + This is emitted whenever a surface's creation, movement, or resizing + results in some part of it being within the scanout region of an + output. + + Note that a surface may be overlapping with zero or more outputs. + + + + + + + This is emitted whenever a surface's creation, movement, or resizing + results in it no longer having any part of it within the scanout region + of an output. + + + + + + + + + This request sets an optional transformation on how the compositor + interprets the contents of the buffer attached to the surface. The + accepted values for the transform parameter are the values for + wl_output.transform. + + Buffer transform is double-buffered state, see wl_surface.commit. + + A newly created surface has its buffer transformation set to normal. + + wl_surface.set_buffer_transform changes the pending buffer + transformation. wl_surface.commit copies the pending buffer + transformation to the current one. Otherwise, the pending and current + values are never changed. + + The purpose of this request is to allow clients to render content + according to the output transform, thus permitting the compositor to + use certain optimizations even if the display is rotated. Using + hardware overlays and scanning out a client buffer for fullscreen + surfaces are examples of such optimizations. Those optimizations are + highly dependent on the compositor implementation, so the use of this + request should be considered on a case-by-case basis. + + Note that if the transform value includes 90 or 270 degree rotation, + the width of the buffer will become the surface height and the height + of the buffer will become the surface width. + + If transform is not one of the values from the + wl_output.transform enum the invalid_transform protocol error + is raised. + + + + + + + + + This request sets an optional scaling factor on how the compositor + interprets the contents of the buffer attached to the window. + + Buffer scale is double-buffered state, see wl_surface.commit. + + A newly created surface has its buffer scale set to 1. + + wl_surface.set_buffer_scale changes the pending buffer scale. + wl_surface.commit copies the pending buffer scale to the current one. + Otherwise, the pending and current values are never changed. + + The purpose of this request is to allow clients to supply higher + resolution buffer data for use on high resolution outputs. It is + intended that you pick the same buffer scale as the scale of the + output that the surface is displayed on. This means the compositor + can avoid scaling when rendering the surface on that output. + + Note that if the scale is larger than 1, then you have to attach + a buffer that is larger (by a factor of scale in each dimension) + than the desired surface size. + + If scale is not positive the invalid_scale protocol error is + raised. + + + + + + + + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. + + Damage is double-buffered state, see wl_surface.commit. + + The damage rectangle is specified in buffer coordinates, + where x and y specify the upper left corner of the damage rectangle. + + The initial value for pending damage is empty: no damage. + wl_surface.damage_buffer adds pending damage: the new pending + damage is the union of old pending damage and the given rectangle. + + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. + + This request differs from wl_surface.damage in only one way - it + takes damage in buffer coordinates instead of surface-local + coordinates. While this generally is more intuitive than surface + coordinates, it is especially desirable when using wp_viewport + or when a drawing library (like EGL) is unaware of buffer scale + and buffer transform. + + Note: Because buffer transformation changes and damage requests may + be interleaved in the protocol stream, it is impossible to determine + the actual mapping between surface and buffer damage until + wl_surface.commit time. Therefore, compositors wishing to take both + kinds of damage into account will have to accumulate damage from the + two requests separately and only transform from one to the other + after receiving the wl_surface.commit. + + + + + + + + + + + + A seat is a group of keyboards, pointer and touch devices. This + object is published as a global during start up, or when such a + device is hot plugged. A seat typically has a pointer and + maintains a keyboard focus and a pointer focus. + + + + + This is a bitmask of capabilities this seat has; if a member is + set, then it is present on the seat. + + + + + + + + + This is emitted whenever a seat gains or loses the pointer, + keyboard or touch capabilities. The argument is a capability + enum containing the complete set of capabilities this seat has. + + When the pointer capability is added, a client may create a + wl_pointer object using the wl_seat.get_pointer request. This object + will receive pointer events until the capability is removed in the + future. + + When the pointer capability is removed, a client should destroy the + wl_pointer objects associated with the seat where the capability was + removed, using the wl_pointer.release request. No further pointer + events will be received on these objects. + + In some compositors, if a seat regains the pointer capability and a + client has a previously obtained wl_pointer object of version 4 or + less, that object may start sending pointer events again. This + behavior is considered a misinterpretation of the intended behavior + and must not be relied upon by the client. wl_pointer objects of + version 5 or later must not send events if created before the most + recent event notifying the client of an added pointer capability. + + The above behavior also applies to wl_keyboard and wl_touch with the + keyboard and touch capabilities, respectively. + + + + + + + The ID provided will be initialized to the wl_pointer interface + for this seat. + + This request only takes effect if the seat has the pointer + capability, or has had the pointer capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the pointer capability. + + + + + + + The ID provided will be initialized to the wl_keyboard interface + for this seat. + + This request only takes effect if the seat has the keyboard + capability, or has had the keyboard capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the keyboard capability. + + + + + + + The ID provided will be initialized to the wl_touch interface + for this seat. + + This request only takes effect if the seat has the touch + capability, or has had the touch capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the touch capability. + + + + + + + + + In a multiseat configuration this can be used by the client to help + identify which physical devices the seat represents. Based on + the seat configuration used by the compositor. + + + + + + + + + Using this request a client can tell the server that it is not going to + use the seat object anymore. + + + + + + + + The wl_pointer interface represents one or more input devices, + such as mice, which control the pointer location and pointer_focus + of a seat. + + The wl_pointer interface generates motion, enter and leave + events for the surfaces that the pointer is located over, + and button and axis events for button presses, button releases + and scrolling. + + + + + + + + + Set the pointer surface, i.e., the surface that contains the + pointer image (cursor). This request gives the surface the role + of a cursor. If the surface already has another role, it raises + a protocol error. + + The cursor actually changes only if the pointer + focus for this device is one of the requesting client's surfaces + or the surface parameter is the current pointer surface. If + there was a previous surface set with this request it is + replaced. If surface is NULL, the pointer image is hidden. + + The parameters hotspot_x and hotspot_y define the position of + the pointer surface relative to the pointer location. Its + top-left corner is always at (x, y) - (hotspot_x, hotspot_y), + where (x, y) are the coordinates of the pointer location, in + surface-local coordinates. + + On surface.attach requests to the pointer surface, hotspot_x + and hotspot_y are decremented by the x and y parameters + passed to the request. Attach must be confirmed by + wl_surface.commit as usual. + + The hotspot can also be updated by passing the currently set + pointer surface to this request with new values for hotspot_x + and hotspot_y. + + The current and pending input regions of the wl_surface are + cleared, and wl_surface.set_input_region is ignored until the + wl_surface is no longer used as the cursor. When the use as a + cursor ends, the current and pending input regions become + undefined, and the wl_surface is unmapped. + + + + + + + + + + + Notification that this seat's pointer is focused on a certain + surface. + + When a seat's focus enters a surface, the pointer image + is undefined and a client should respond to this event by setting + an appropriate pointer image with the set_cursor request. + + + + + + + + + + + Notification that this seat's pointer is no longer focused on + a certain surface. + + The leave notification is sent before the enter notification + for the new focus. + + + + + + + + Notification of pointer location change. The arguments + surface_x and surface_y are the location relative to the + focused surface. + + + + + + + + + + Describes the physical state of a button that produced the button + event. + + + + + + + + Mouse button click and release notifications. + + The location of the click is given by the last motion or + enter event. + The time argument is a timestamp with millisecond + granularity, with an undefined base. + + + + + + + + + + + Describes the axis types of scroll events. + + + + + + + + Scroll and other axis notifications. + + For scroll events (vertical and horizontal scroll axes), the + value parameter is the length of a vector along the specified + axis in a coordinate space identical to those of motion events, + representing a relative movement along the specified axis. + + For devices that support movements non-parallel to axes multiple + axis events will be emitted. + + When applicable, for example for touch pads, the server can + choose to emit scroll events where the motion vector is + equivalent to a motion event vector. + + When applicable, a client can transform its content relative to the + scroll distance. + + + + + + + + + + + + Using this request a client can tell the server that it is not going to + use the pointer object anymore. + + This request destroys the pointer proxy object, so clients must not call + wl_pointer_destroy() after using this request. + + + + + + + + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. + + All wl_pointer events before a wl_pointer.frame event belong + logically together. For example, in a diagonal scroll motion the + compositor will send an optional wl_pointer.axis_source event, two + wl_pointer.axis events (horizontal and vertical) and finally a + wl_pointer.frame event. The client may use this information to + calculate a diagonal vector for scrolling. + + When multiple wl_pointer.axis events occur within the same frame, + the motion vector is the combined motion of all events. + When a wl_pointer.axis and a wl_pointer.axis_stop event occur within + the same frame, this indicates that axis movement in one axis has + stopped but continues in the other axis. + When multiple wl_pointer.axis_stop events occur within the same + frame, this indicates that these axes stopped in the same instance. + + A wl_pointer.frame event is sent for every logical event group, + even if the group only contains a single wl_pointer event. + Specifically, a client may get a sequence: motion, frame, button, + frame, axis, frame, axis_stop, frame. + + The wl_pointer.enter and wl_pointer.leave events are logical events + generated by the compositor and not the hardware. These events are + also grouped by a wl_pointer.frame. When a pointer moves from one + surface to another, a compositor should group the + wl_pointer.leave event within the same wl_pointer.frame. + However, a client must not rely on wl_pointer.leave and + wl_pointer.enter being in the same wl_pointer.frame. + Compositor-specific policies may require the wl_pointer.leave and + wl_pointer.enter event being split across multiple wl_pointer.frame + groups. + + + + + + Describes the source types for axis events. This indicates to the + client how an axis event was physically generated; a client may + adjust the user interface accordingly. For example, scroll events + from a "finger" source may be in a smooth coordinate space with + kinetic scrolling whereas a "wheel" source may be in discrete steps + of a number of lines. + + The "continuous" axis source is a device generating events in a + continuous coordinate space, but using something other than a + finger. One example for this source is button-based scrolling where + the vertical motion of a device is converted to scroll events while + a button is held down. + + + + + + + + + Source information for scroll and other axes. + + This event does not occur on its own. It is sent before a + wl_pointer.frame event and carries the source information for + all events within that frame. + + The source specifies how this event was generated. If the source is + wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be + sent when the user lifts the finger off the device. + + If the source is wl_pointer axis_source.wheel or + wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may + or may not be sent. Whether a compositor sends an axis_stop event + for these sources is hardware-specific and implementation-dependent; + clients must not rely on receiving an axis_stop event for these + scroll sources and should treat scroll sequences from these scroll + sources as unterminated by default. + + This event is optional. If the source is unknown for a particular + axis event sequence, no event is sent. + Only one wl_pointer.axis_source event is permitted per frame. + + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. + + + + + + + Stop notification for scroll and other axes. + + For some wl_pointer.axis_source types, a wl_pointer.axis_stop event + is sent to notify a client that the axis sequence has terminated. + This enables the client to implement kinetic scrolling. + See the wl_pointer.axis_source documentation for information on when + this event may be generated. + + Any wl_pointer.axis events with the same axis_source after this + event should be considered as the start of a new axis motion. + + The timestamp is to be interpreted identical to the timestamp in the + wl_pointer.axis event. The timestamp value may be the same as a + preceding wl_pointer.axis event. + + + + + + + + Discrete step information for scroll and other axes. + + This event carries the axis value of the wl_pointer.axis event in + discrete steps (e.g. mouse wheel clicks). + + This event does not occur on its own, it is coupled with a + wl_pointer.axis event that represents this axis value on a + continuous scale. The protocol guarantees that each axis_discrete + event is always followed by exactly one axis event with the same + axis number within the same wl_pointer.frame. Note that the protocol + allows for other events to occur between the axis_discrete and + its coupled axis event, including other axis_discrete or axis + events. + + This event is optional; continuous scrolling devices + like two-finger scrolling on touchpads do not have discrete + steps and do not generate this event. + + The discrete value carries the directional information. e.g. a value + of -2 is two steps towards the negative direction of this axis. + + The axis number is identical to the axis number in the associated + axis event. + + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. + + + + + + + + + The wl_keyboard interface represents one or more keyboards + associated with a seat. + + + + + This specifies the format of the keymap provided to the + client with the wl_keyboard.keymap event. + + + + + + + + This event provides a file descriptor to the client which can be + memory-mapped to provide a keyboard mapping description. + + + + + + + + + Notification that this seat's keyboard focus is on a certain + surface. + + + + + + + + + Notification that this seat's keyboard focus is no longer on + a certain surface. + + The leave notification is sent before the enter notification + for the new focus. + + + + + + + + Describes the physical state of a key that produced the key event. + + + + + + + + A key was pressed or released. + The time argument is a timestamp with millisecond + granularity, with an undefined base. + + + + + + + + + + + Notifies clients that the modifier and/or group state has + changed, and it should update its local state. + + + + + + + + + + + + + + + + + + + + Informs the client about the keyboard's repeat rate and delay. + + This event is sent as soon as the wl_keyboard object has been created, + and is guaranteed to be received by the client before any key press + event. + + Negative values for either rate or delay are illegal. A rate of zero + will disable any repeating (regardless of the value of delay). + + This event can be sent later on as well with a new value if necessary, + so clients should continue listening for the event past the creation + of wl_keyboard. + + + + + + + + + + The wl_touch interface represents a touchscreen + associated with a seat. + + Touch interactions can consist of one or more contacts. + For each contact, a series of events is generated, starting + with a down event, followed by zero or more motion events, + and ending with an up event. Events relating to the same + contact point can be identified by the ID of the sequence. + + + + + A new touch point has appeared on the surface. This touch point is + assigned a unique ID. Future events from this touch point reference + this ID. The ID ceases to be valid after a touch up event and may be + reused in the future. + + + + + + + + + + + + The touch point has disappeared. No further events will be sent for + this touch point and the touch point's ID is released and may be + reused in a future touch down event. + + + + + + + + + A touch point has changed coordinates. + + + + + + + + + + Indicates the end of a contact point list. + + + + + + Sent if the compositor decides the touch stream is a global + gesture. No further events are sent to the clients from that + particular gesture. Touch cancellation applies to all touch points + currently active on this client's surface. The client is + responsible for finalizing the touch points, future touch points on + this surface may reuse the touch point ID. + + + + + + + + + + + + + An output describes part of the compositor geometry. The + compositor works in the 'compositor coordinate system' and an + output corresponds to a rectangular area in that space that is + actually visible. This typically corresponds to a monitor that + displays part of the compositor space. This object is published + as global during start up, or when a monitor is hotplugged. + + + + + This enumeration describes how the physical + pixels on an output are laid out. + + + + + + + + + + + + This describes the transform that a compositor will apply to a + surface to compensate for the rotation or mirroring of an + output device. + + The flipped values correspond to an initial flip around a + vertical axis followed by rotation. + + The purpose is mainly to allow clients to render accordingly and + tell the compositor, so that for fullscreen surfaces, the + compositor will still be able to scan out directly from client + surfaces. + + + + + + + + + + + + + + + The geometry event describes geometric properties of the output. + The event is sent when binding to the output object and whenever + any of the properties change. + + + + + + + + + + + + + + These flags describe properties of an output mode. + They are used in the flags bitfield of the mode event. + + + + + + + + The mode event describes an available mode for the output. + + The event is sent when binding to the output object and there + will always be one mode, the current mode. The event is sent + again if an output changes mode, for the mode that is now + current. In other words, the current mode is always the last + mode that was received with the current flag set. + + The size of a mode is given in physical hardware units of + the output device. This is not necessarily the same as + the output size in the global compositor space. For instance, + the output may be scaled, as described in wl_output.scale, + or transformed, as described in wl_output.transform. + + + + + + + + + + + + This event is sent after all other properties have been + sent after binding to the output object and after any + other property changes done after that. This allows + changes to the output properties to be seen as + atomic, even if they happen via multiple events. + + + + + + This event contains scaling geometry information + that is not in the geometry event. It may be sent after + binding the output object or if the output scale changes + later. If it is not sent, the client should assume a + scale of 1. + + A scale larger than 1 means that the compositor will + automatically scale surface buffers by this amount + when rendering. This is used for very high resolution + displays where applications rendering at the native + resolution would be too small to be legible. + + It is intended that scaling aware clients track the + current output of a surface, and if it is on a scaled + output it should use wl_surface.set_buffer_scale with + the scale of the output. That way the compositor can + avoid scaling the surface, and the client can supply + a higher detail image. + + + + + + + + + Using this request a client can tell the server that it is not going to + use the output object anymore. + + + + + + + A region object describes an area. + + Region objects are used to describe the opaque and input + regions of a surface. + + + + + Destroy the region. This will invalidate the object ID. + + + + + + Add the specified rectangle to the region. + + + + + + + + + + + Subtract the specified rectangle from the region. + + + + + + + + + + + + The global interface exposing sub-surface compositing capabilities. + A wl_surface, that has sub-surfaces associated, is called the + parent surface. Sub-surfaces can be arbitrarily nested and create + a tree of sub-surfaces. + + The root surface in a tree of sub-surfaces is the main + surface. The main surface cannot be a sub-surface, because + sub-surfaces must always have a parent. + + A main surface with its sub-surfaces forms a (compound) window. + For window management purposes, this set of wl_surface objects is + to be considered as a single window, and it should also behave as + such. + + The aim of sub-surfaces is to offload some of the compositing work + within a window from clients to the compositor. A prime example is + a video player with decorations and video in separate wl_surface + objects. This should allow the compositor to pass YUV video buffer + processing to dedicated overlay hardware when possible. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other + objects, wl_subsurface objects included. + + + + + + + + + + Create a sub-surface interface for the given surface, and + associate it with the given parent surface. This turns a + plain wl_surface into a sub-surface. + + The to-be sub-surface must not already have another role, and it + must not have an existing wl_subsurface object. Otherwise a protocol + error is raised. + + + + + + + + + + + An additional interface to a wl_surface object, which has been + made a sub-surface. A sub-surface has one parent surface. A + sub-surface's size and position are not limited to that of the parent. + Particularly, a sub-surface is not automatically clipped to its + parent's area. + + A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + and the parent surface is mapped. The order of which one happens + first is irrelevant. A sub-surface is hidden if the parent becomes + hidden, or if a NULL wl_buffer is applied. These rules apply + recursively through the tree of surfaces. + + The behaviour of a wl_surface.commit request on a sub-surface + depends on the sub-surface's mode. The possible modes are + synchronized and desynchronized, see methods + wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + mode caches the wl_surface state to be applied when the parent's + state gets applied, and desynchronized mode applies the pending + wl_surface state directly. A sub-surface is initially in the + synchronized mode. + + Sub-surfaces have also other kind of state, which is managed by + wl_subsurface requests, as opposed to wl_surface requests. This + state includes the sub-surface position relative to the parent + surface (wl_subsurface.set_position), and the stacking order of + the parent and its sub-surfaces (wl_subsurface.place_above and + .place_below). This state is applied when the parent surface's + wl_surface state is applied, regardless of the sub-surface's mode. + As the exception, set_sync and set_desync are effective immediately. + + The main surface can be thought to be always in desynchronized mode, + since it does not have a parent in the sub-surfaces sense. + + Even if a sub-surface is in desynchronized mode, it will behave as + in synchronized mode, if its parent surface behaves as in + synchronized mode. This rule is applied recursively throughout the + tree of surfaces. This means, that one can set a sub-surface into + synchronized mode, and then assume that all its child and grand-child + sub-surfaces are synchronized, too, without explicitly setting them. + + If the wl_surface associated with the wl_subsurface is destroyed, the + wl_subsurface object becomes inert. Note, that destroying either object + takes effect immediately. If you need to synchronize the removal + of a sub-surface to the parent surface update, unmap the sub-surface + first by attaching a NULL wl_buffer, update parent, and then destroy + the sub-surface. + + If the parent wl_surface object is destroyed, the sub-surface is + unmapped. + + + + + The sub-surface interface is removed from the wl_surface object + that was turned into a sub-surface with a + wl_subcompositor.get_subsurface request. The wl_surface's association + to the parent is deleted, and the wl_surface loses its role as + a sub-surface. The wl_surface is unmapped. + + + + + + + + + + This schedules a sub-surface position change. + The sub-surface will be moved so that its origin (top left + corner pixel) will be at the location x, y of the parent surface + coordinate system. The coordinates are not restricted to the parent + surface area. Negative values are allowed. + + The scheduled coordinates will take effect whenever the state of the + parent surface is applied. When this happens depends on whether the + parent surface is in synchronized mode or not. See + wl_subsurface.set_sync and wl_subsurface.set_desync for details. + + If more than one set_position request is invoked by the client before + the commit of the parent surface, the position of a new request always + replaces the scheduled position from any previous request. + + The initial position is 0, 0. + + + + + + + + + This sub-surface is taken from the stack, and put back just + above the reference surface, changing the z-order of the sub-surfaces. + The reference surface must be one of the sibling surfaces, or the + parent surface. Using any other surface, including this sub-surface, + will cause a protocol error. + + The z-order is double-buffered. Requests are handled in order and + applied immediately to a pending state. The final pending state is + copied to the active state the next time the state of the parent + surface is applied. When this happens depends on whether the parent + surface is in synchronized mode or not. See wl_subsurface.set_sync and + wl_subsurface.set_desync for details. + + A new sub-surface is initially added as the top-most in the stack + of its siblings and parent. + + + + + + + + The sub-surface is placed just below the reference surface. + See wl_subsurface.place_above. + + + + + + + + Change the commit behaviour of the sub-surface to synchronized + mode, also described as the parent dependent mode. + + In synchronized mode, wl_surface.commit on a sub-surface will + accumulate the committed state in a cache, but the state will + not be applied and hence will not change the compositor output. + The cached state is applied to the sub-surface immediately after + the parent surface's state is applied. This ensures atomic + updates of the parent and all its synchronized sub-surfaces. + Applying the cached state will invalidate the cache, so further + parent surface commits do not (re-)apply old state. + + See wl_subsurface for the recursive effect of this mode. + + + + + + Change the commit behaviour of the sub-surface to desynchronized + mode, also described as independent or freely running mode. + + In desynchronized mode, wl_surface.commit on a sub-surface will + apply the pending state directly, without caching, as happens + normally with a wl_surface. Calling wl_surface.commit on the + parent surface has no effect on the sub-surface's wl_surface + state. This mode allows a sub-surface to be updated on its own. + + If cached state exists when wl_surface.commit is called in + desynchronized mode, the pending state is added to the cached + state, and applied as a whole. This invalidates the cache. + + Note: even if a sub-surface is set to desynchronized, a parent + sub-surface may override it to behave as synchronized. For details, + see wl_subsurface. + + If a surface's parent surface behaves as desynchronized, then + the cached state is applied on set_desync. + + + + + diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h new file mode 100644 index 00000000..8d02edb7 --- /dev/null +++ b/tests/data/small-client-core.h @@ -0,0 +1,172 @@ +/* SCANNER TEST */ + +#ifndef SMALL_TEST_CLIENT_PROTOCOL_H +#define SMALL_TEST_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_small_test The small_test protocol + * @section page_ifaces_small_test Interfaces + * - @subpage page_iface_intf_A - the thing A + * @section page_copyright_small_test Copyright + *
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct another_intf; +struct intf_A; +struct intf_not_here; + +/** + * @page page_iface_intf_A intf_A + * @section page_iface_intf_A_desc Description + * + * A useless example trying to tickle the scanner. + * @section page_iface_intf_A_api API + * See @ref iface_intf_A. + */ +/** + * @defgroup iface_intf_A The intf_A interface + * + * A useless example trying to tickle the scanner. + */ +extern const struct wl_interface intf_A_interface; + +/** + * @ingroup iface_intf_A + * @struct intf_A_listener + */ +struct intf_A_listener { + /** + */ + void (*hey)(void *data, + struct intf_A *intf_A); +}; + +/** + * @ingroup iface_intf_A + */ +static inline int +intf_A_add_listener(struct intf_A *intf_A, + const struct intf_A_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) intf_A, + (void (**)(void)) listener, data); +} + +#define INTF_A_RQ1 0 +#define INTF_A_RQ2 1 +#define INTF_A_DESTROY 2 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_HEY_SINCE_VERSION 1 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ1_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ2_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_intf_A */ +static inline void +intf_A_set_user_data(struct intf_A *intf_A, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) intf_A, user_data); +} + +/** @ingroup iface_intf_A */ +static inline void * +intf_A_get_user_data(struct intf_A *intf_A) +{ + return wl_proxy_get_user_data((struct wl_proxy *) intf_A); +} + +static inline uint32_t +intf_A_get_version(struct intf_A *intf_A) +{ + return wl_proxy_get_version((struct wl_proxy *) intf_A); +} + +/** + * @ingroup iface_intf_A + */ +static inline void * +intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t version) +{ + struct wl_proxy *untyped_new; + + untyped_new = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) intf_A, + INTF_A_RQ1, interface, version, interface->name, version, NULL); + + return (void *) untyped_new; +} + +/** + * @ingroup iface_intf_A + */ +static inline struct intf_not_here * +intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct another_intf *obj) +{ + struct wl_proxy *typed_new; + + typed_new = wl_proxy_marshal_constructor((struct wl_proxy *) intf_A, + INTF_A_RQ2, &intf_not_here_interface, NULL, str, i, u, f, fd, obj); + + return (struct intf_not_here *) typed_new; +} + +/** + * @ingroup iface_intf_A + */ +static inline void +intf_A_destroy(struct intf_A *intf_A) +{ + wl_proxy_marshal((struct wl_proxy *) intf_A, + INTF_A_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) intf_A); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/small-client.h b/tests/data/small-client.h new file mode 100644 index 00000000..050e63ff --- /dev/null +++ b/tests/data/small-client.h @@ -0,0 +1,172 @@ +/* SCANNER TEST */ + +#ifndef SMALL_TEST_CLIENT_PROTOCOL_H +#define SMALL_TEST_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_small_test The small_test protocol + * @section page_ifaces_small_test Interfaces + * - @subpage page_iface_intf_A - the thing A + * @section page_copyright_small_test Copyright + *
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct another_intf; +struct intf_A; +struct intf_not_here; + +/** + * @page page_iface_intf_A intf_A + * @section page_iface_intf_A_desc Description + * + * A useless example trying to tickle the scanner. + * @section page_iface_intf_A_api API + * See @ref iface_intf_A. + */ +/** + * @defgroup iface_intf_A The intf_A interface + * + * A useless example trying to tickle the scanner. + */ +extern const struct wl_interface intf_A_interface; + +/** + * @ingroup iface_intf_A + * @struct intf_A_listener + */ +struct intf_A_listener { + /** + */ + void (*hey)(void *data, + struct intf_A *intf_A); +}; + +/** + * @ingroup iface_intf_A + */ +static inline int +intf_A_add_listener(struct intf_A *intf_A, + const struct intf_A_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) intf_A, + (void (**)(void)) listener, data); +} + +#define INTF_A_RQ1 0 +#define INTF_A_RQ2 1 +#define INTF_A_DESTROY 2 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_HEY_SINCE_VERSION 1 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ1_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ2_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_intf_A */ +static inline void +intf_A_set_user_data(struct intf_A *intf_A, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) intf_A, user_data); +} + +/** @ingroup iface_intf_A */ +static inline void * +intf_A_get_user_data(struct intf_A *intf_A) +{ + return wl_proxy_get_user_data((struct wl_proxy *) intf_A); +} + +static inline uint32_t +intf_A_get_version(struct intf_A *intf_A) +{ + return wl_proxy_get_version((struct wl_proxy *) intf_A); +} + +/** + * @ingroup iface_intf_A + */ +static inline void * +intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t version) +{ + struct wl_proxy *untyped_new; + + untyped_new = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) intf_A, + INTF_A_RQ1, interface, version, interface->name, version, NULL); + + return (void *) untyped_new; +} + +/** + * @ingroup iface_intf_A + */ +static inline struct intf_not_here * +intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct another_intf *obj) +{ + struct wl_proxy *typed_new; + + typed_new = wl_proxy_marshal_constructor((struct wl_proxy *) intf_A, + INTF_A_RQ2, &intf_not_here_interface, NULL, str, i, u, f, fd, obj); + + return (struct intf_not_here *) typed_new; +} + +/** + * @ingroup iface_intf_A + */ +static inline void +intf_A_destroy(struct intf_A *intf_A) +{ + wl_proxy_marshal((struct wl_proxy *) intf_A, + INTF_A_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) intf_A); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/small-code-core.c b/tests/data/small-code-core.c new file mode 100644 index 00000000..dbf7f401 --- /dev/null +++ b/tests/data/small-code-core.c @@ -0,0 +1,61 @@ +/* SCANNER TEST */ + +/* + * Copyright © 2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface another_intf_interface; +extern const struct wl_interface intf_not_here_interface; + +static const struct wl_interface *types[] = { + NULL, + &intf_not_here_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &another_intf_interface, +}; + +static const struct wl_message intf_A_requests[] = { + { "rq1", "sun", types + 0 }, + { "rq2", "nsiufho", types + 1 }, + { "destroy", "", types + 0 }, +}; + +static const struct wl_message intf_A_events[] = { + { "hey", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface intf_A_interface = { + "intf_A", 1, + 3, intf_A_requests, + 1, intf_A_events, +}; + diff --git a/tests/data/small-code.c b/tests/data/small-code.c new file mode 100644 index 00000000..dbf7f401 --- /dev/null +++ b/tests/data/small-code.c @@ -0,0 +1,61 @@ +/* SCANNER TEST */ + +/* + * Copyright © 2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface another_intf_interface; +extern const struct wl_interface intf_not_here_interface; + +static const struct wl_interface *types[] = { + NULL, + &intf_not_here_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &another_intf_interface, +}; + +static const struct wl_message intf_A_requests[] = { + { "rq1", "sun", types + 0 }, + { "rq2", "nsiufho", types + 1 }, + { "destroy", "", types + 0 }, +}; + +static const struct wl_message intf_A_events[] = { + { "hey", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface intf_A_interface = { + "intf_A", 1, + 3, intf_A_requests, + 1, intf_A_events, +}; + diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h new file mode 100644 index 00000000..c1e8d05a --- /dev/null +++ b/tests/data/small-server-core.h @@ -0,0 +1,131 @@ +/* SCANNER TEST */ + +#ifndef SMALL_TEST_SERVER_PROTOCOL_H +#define SMALL_TEST_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_small_test The small_test protocol + * @section page_ifaces_small_test Interfaces + * - @subpage page_iface_intf_A - the thing A + * @section page_copyright_small_test Copyright + *
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct another_intf; +struct intf_A; +struct intf_not_here; + +/** + * @page page_iface_intf_A intf_A + * @section page_iface_intf_A_desc Description + * + * A useless example trying to tickle the scanner. + * @section page_iface_intf_A_api API + * See @ref iface_intf_A. + */ +/** + * @defgroup iface_intf_A The intf_A interface + * + * A useless example trying to tickle the scanner. + */ +extern const struct wl_interface intf_A_interface; + +/** + * @ingroup iface_intf_A + * @struct intf_A_interface + */ +struct intf_A_interface { + /** + * @param interface name of the objects interface + * @param version version of the objects interface + */ + void (*rq1)(struct wl_client *client, + struct wl_resource *resource, + const char *interface, uint32_t version, uint32_t untyped_new); + /** + */ + void (*rq2)(struct wl_client *client, + struct wl_resource *resource, + uint32_t typed_new, + const char *str, + int32_t i, + uint32_t u, + wl_fixed_t f, + int32_t fd, + struct wl_resource *obj); + /** + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define INTF_A_HEY 0 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_HEY_SINCE_VERSION 1 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ1_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ2_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_DESTROY_SINCE_VERSION 1 + +/** + * @ingroup iface_intf_A + * Sends an hey event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +intf_A_send_hey(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, INTF_A_HEY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/small-server.h b/tests/data/small-server.h new file mode 100644 index 00000000..0bd8a1d9 --- /dev/null +++ b/tests/data/small-server.h @@ -0,0 +1,131 @@ +/* SCANNER TEST */ + +#ifndef SMALL_TEST_SERVER_PROTOCOL_H +#define SMALL_TEST_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_small_test The small_test protocol + * @section page_ifaces_small_test Interfaces + * - @subpage page_iface_intf_A - the thing A + * @section page_copyright_small_test Copyright + *
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct another_intf; +struct intf_A; +struct intf_not_here; + +/** + * @page page_iface_intf_A intf_A + * @section page_iface_intf_A_desc Description + * + * A useless example trying to tickle the scanner. + * @section page_iface_intf_A_api API + * See @ref iface_intf_A. + */ +/** + * @defgroup iface_intf_A The intf_A interface + * + * A useless example trying to tickle the scanner. + */ +extern const struct wl_interface intf_A_interface; + +/** + * @ingroup iface_intf_A + * @struct intf_A_interface + */ +struct intf_A_interface { + /** + * @param interface name of the objects interface + * @param version version of the objects interface + */ + void (*rq1)(struct wl_client *client, + struct wl_resource *resource, + const char *interface, uint32_t version, uint32_t untyped_new); + /** + */ + void (*rq2)(struct wl_client *client, + struct wl_resource *resource, + uint32_t typed_new, + const char *str, + int32_t i, + uint32_t u, + wl_fixed_t f, + int32_t fd, + struct wl_resource *obj); + /** + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define INTF_A_HEY 0 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_HEY_SINCE_VERSION 1 + +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ1_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_RQ2_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_DESTROY_SINCE_VERSION 1 + +/** + * @ingroup iface_intf_A + * Sends an hey event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +intf_A_send_hey(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, INTF_A_HEY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/small.xml b/tests/data/small.xml new file mode 100644 index 00000000..571618f1 --- /dev/null +++ b/tests/data/small.xml @@ -0,0 +1,52 @@ + + + + + Copyright © 2016 Collabora, Ltd. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + + + + A useless example trying to tickle the scanner. + + + + + + + + + + + + + + + + + + + + + From c9f64544a3b5f217c776bb959971a4e061eb15de Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 30 Sep 2016 15:12:47 +0300 Subject: [PATCH 0405/1152] tests: add scanner tests Add tests that ensure that wayland-scanner output for a given input does not change unexpectedly. This makes it very easy to review wayland-scanner patches. Before, when patches were proposed for wayland-scanner, I had to build wayland without the patches, save the generated files into a temporary directory, apply the patches, build again, and diff the old vs. new generated file. No more. Now whenever someone makes intentional changes to wayland-scanner's output, he will also have to patch the example output files to match. That means that reviewers see the diff of the generated files straight from the patch itself. Verifying the diff is true is as easy as 'make check'. The tests use separate example XML files instead of wayland.xml directly, so that wayland.xml can be updated without fixing scanner tests, avoiding the churn. example.xml starts as a copy of wayland.xml. If wayland.xml starts using new wayland-scanner features, they should be copied into example.xml again to be covered by the tests. This patch relies on the previous patch to actually add all the data files for input and reference output. The scanner output is fed through sed to remove parts that are allowed to vary: the scanner version string. v2: no need for scanner-test.sh to depend on the test data Task: https://phabricator.freedesktop.org/T3313 Signed-off-by: Pekka Paalanen Reviewed-by: Emilio Pozuelo Monfort (v1) Reviewed-by: Yong Bakos Tested-by: Yong Bakos --- .gitignore | 1 + Makefile.am | 29 +++++++++++++++++++++++- tests/scanner-test.sh | 51 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100755 tests/scanner-test.sh diff --git a/.gitignore b/.gitignore index 33e809cc..8da9861b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ ctags /missing /stamp-h1 /test-driver +/tests/output/ Makefile Makefile.in exec-fd-leak-checker diff --git a/Makefile.am b/Makefile.am index 87bab0da..d78a0ca5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -169,7 +169,15 @@ if ENABLE_CPP_TEST built_test_programs += cpp-compile-test endif -TESTS = $(built_test_programs) +AM_TESTS_ENVIRONMENT = \ + export WAYLAND_SCANNER='$(top_builddir)/wayland-scanner' \ + TEST_DATA_DIR='$(top_srcdir)/tests/data' \ + TEST_OUTPUT_DIR='$(top_builddir)/tests/output' \ + SED=$(SED) \ + ; + +TESTS = $(built_test_programs) \ + tests/scanner-test.sh noinst_PROGRAMS = \ $(built_test_programs) \ @@ -246,4 +254,23 @@ os_wrappers_test_LDADD = libtest-runner.la exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la + +EXTRA_DIST += tests/scanner-test.sh \ + tests/data/example.xml \ + tests/data/example-client.h \ + tests/data/example-server.h \ + tests/data/example-code.c \ + tests/data/small.xml \ + tests/data/small-code.c \ + tests/data/small-client.h \ + tests/data/small-server.h \ + tests/data/small-code-core.c \ + tests/data/small-client-core.h \ + tests/data/small-server-core.h + +tests/scanner-test.sh: $(top_builddir)/wayland-scanner + +clean-local: + -rm -rf tests/output + endif #ENABLE_LIBRARIES diff --git a/tests/scanner-test.sh b/tests/scanner-test.sh new file mode 100755 index 00000000..7854b864 --- /dev/null +++ b/tests/scanner-test.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +echo "srcdir: $srcdir" +echo "scanner: $WAYLAND_SCANNER" +echo "test_data_dir: $TEST_DATA_DIR" +echo "test_output_dir: $TEST_OUTPUT_DIR" +echo "pwd: $PWD" +echo "sed: $SED" + +RETCODE=0 + +hard_fail() { + echo "$@" "ERROR" + exit 99 +} + +fail() { + echo "$@" "FAIL" + RETCODE=1 +} + +mkdir -p "$TEST_OUTPUT_DIR" || hard_fail "setup" + +generate_and_compare() { + echo + echo "Testing $1 generation: $2 -> $3" + + "$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_OUTPUT_DIR/$3" || \ + hard_fail "$2 -> $3" + + "$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \ + "$TEST_OUTPUT_DIR/$3" || hard_fail "$2 -> $3" + + diff -q "$TEST_DATA_DIR/$3" "$TEST_OUTPUT_DIR/$3" && \ + echo "$2 -> $3 PASS" || \ + fail "$2 -> $3" +} + +generate_and_compare "code" "example.xml" "example-code.c" +generate_and_compare "client-header" "example.xml" "example-client.h" +generate_and_compare "server-header" "example.xml" "example-server.h" + +generate_and_compare "code" "small.xml" "small-code.c" +generate_and_compare "client-header" "small.xml" "small-client.h" +generate_and_compare "server-header" "small.xml" "small-server.h" + +generate_and_compare "-c code" "small.xml" "small-code-core.c" +generate_and_compare "-c client-header" "small.xml" "small-client-core.h" +generate_and_compare "-c server-header" "small.xml" "small-server-core.h" + +exit $RETCODE From 20742b74490bd80ef62b888157df37af92a21e99 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 22 Nov 2016 08:13:43 -0800 Subject: [PATCH 0406/1152] doc: Remove display of WL_PRINTF attribute Doxygen truncates a WL_PRINTF function attribute, and there does not seem to be any workaround[1]. When using the attribute like this: typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0); Doxygen generates something that looks like this: typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, Configure doxygen to consider WL_PRINTF(x,y) as predefined, so it does not display the attribute at all in the generated documentation. [1] https://bugzilla.gnome.org/show_bug.cgi?id=774741 Signed-off-by: Yong Bakos Reviewed-by: Peter Hutterer --- doc/doxygen/wayland.doxygen.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in index 9d7fa0c4..3913a135 100644 --- a/doc/doxygen/wayland.doxygen.in +++ b/doc/doxygen/wayland.doxygen.in @@ -8,7 +8,8 @@ QUIET = YES HTML_TIMESTAMP = YES GENERATE_LATEX = NO MAN_LINKS = YES -PREDEFINED = WL_EXPORT= +PREDEFINED = WL_EXPORT= \ + WL_PRINTF(x,y)= MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES DOT_MULTI_TARGETS = YES From deb370cc8f834aa93c294b70f2e944dafd692031 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Fri, 25 Nov 2016 10:48:36 -0800 Subject: [PATCH 0407/1152] doc: Remove wayland-util.c from file list Documentation generation via doxygen includes wayland-util.c in its file list. Although functions are documented in wayland-util.h, doxygen is not automatically using the same documentation for functions in wayland-util.c. In addition, everything listed in the doxygen page for wayland-util.c is documented in the page for wayland-util.h and the pages for corresponding structures. As such, the doxygen page for wayland-util.c has no value, and is redundant. Remove the doxygen page for wayland-util.c. Signed-off-by: Yong Bakos Acked-by: Peter Hutterer --- doc/doxygen/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index c3773536..276a395b 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -9,7 +9,6 @@ noinst_DATA = \ dist_noinst_DATA = wayland.doxygen.in scanned_src_files_shared = \ - $(top_srcdir)/src/wayland-util.c \ $(top_srcdir)/src/wayland-util.h scanned_src_files_Client = \ From 721e0b4a9783a965dcb7f926ff595755219351f5 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Tue, 6 Dec 2016 07:21:56 -0800 Subject: [PATCH 0408/1152] util: Document wl_array and wl_list members Despite their clear names, wl_array and wl_list members are undocumented, resulting in doxygen warnings[1] when building documentation. Document these members, suppressing the warnings. [1] Warnings are visible when EXTRACT_ALL = NO. Signed-off-by: Yong Bakos Reviewed-by: Daniel Stone --- src/wayland-util.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland-util.h b/src/wayland-util.h index f0a45088..caeac826 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -261,7 +261,9 @@ struct wl_interface { * \sa http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/list.h */ struct wl_list { + /** Previous list element */ struct wl_list *prev; + /** Next list element */ struct wl_list *next; }; @@ -490,8 +492,11 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other); * */ struct wl_array { + /** Array size */ size_t size; + /** Allocated space */ size_t alloc; + /** Array data */ void *data; }; From 493eda337ae7cc5530c23833f91f1738690d7ba3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 24 Jan 2017 09:56:36 +1000 Subject: [PATCH 0409/1152] tests: sync example.xml with wayland.xml These are the protocol.xml changes from: 66a26aeb2a: protocol: Remove inconsistent line breaks a26ed0949e: protocol: indentation fixes 6a18a87727: protocol: Extend wl_touch with touchpoint shape and orientation and a few other, smaller ones. Signed-off-by: Peter Hutterer Reviewed-by: Daniel Stone Reviewed-by: Yong Bakos Tested-by: Yong Bakos Reviewed-by: Pekka Paalanen --- tests/data/example-client.h | 112 +++++++++++++++-- tests/data/example-code.c | 12 +- tests/data/example-server.h | 51 ++++++-- tests/data/example.xml | 231 ++++++++++++++++++++++-------------- 4 files changed, 294 insertions(+), 112 deletions(-) diff --git a/tests/data/example-client.h b/tests/data/example-client.h index b2bb24e5..857aacfe 100644 --- a/tests/data/example-client.h +++ b/tests/data/example-client.h @@ -108,8 +108,8 @@ extern const struct wl_interface wl_display_interface; * @page page_iface_wl_registry wl_registry * @section page_iface_wl_registry_desc Description * - * The global registry object. The server has a number of global - * objects that are available to all clients. These objects + * The singleton global registry object. The server has a number of + * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. @@ -134,8 +134,8 @@ extern const struct wl_interface wl_display_interface; /** * @defgroup iface_wl_registry The wl_registry interface * - * The global registry object. The server has a number of global - * objects that are available to all clients. These objects + * The singleton global registry object. The server has a number of + * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. @@ -220,7 +220,7 @@ extern const struct wl_interface wl_shm_pool_interface; * @page page_iface_wl_shm wl_shm * @section page_iface_wl_shm_desc Description * - * A global singleton object that provides support for shared + * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool @@ -235,7 +235,7 @@ extern const struct wl_interface wl_shm_pool_interface; /** * @defgroup iface_wl_shm The wl_shm interface * - * A global singleton object that provides support for shared + * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool @@ -4038,7 +4038,7 @@ enum wl_pointer_axis { */ enum wl_pointer_axis_source { /** - * a physical wheel + * a physical wheel rotation */ WL_POINTER_AXIS_SOURCE_WHEEL = 0, /** @@ -4115,6 +4115,14 @@ struct wl_pointer_listener { * The location of the click is given by the last motion or enter * event. The time argument is a timestamp with millisecond * granularity, with an undefined base. + * + * The button is a button code as defined in the Linux kernel's + * linux/input-event-codes.h header file, e.g. BTN_LEFT. + * + * Any 16-bit button code value is reserved for future additions to + * the kernel's event code list. All other button codes above + * 0xFFFF are currently undefined but may be used in future + * versions of this protocol. * @param serial serial number of the button event * @param time timestamp with millisecond granularity * @param button button that produced the event @@ -4731,7 +4739,14 @@ struct wl_touch_listener { /** * end of touch frame event * - * Indicates the end of a contact point list. + * Indicates the end of a set of events that logically belong + * together. A client is expected to accumulate the data in all + * events within the frame before proceeding. + * + * A wl_touch.frame terminates at least one event but otherwise no + * guarantee is provided about the set of events within a frame. A + * client must assume that any state not updated in a frame is + * unchanged from the previously known state. */ void (*frame)(void *data, struct wl_touch *wl_touch); @@ -4747,6 +4762,79 @@ struct wl_touch_listener { */ void (*cancel)(void *data, struct wl_touch *wl_touch); + /** + * update shape of touch point + * + * Sent when a touchpoint has changed its shape. + * + * This event does not occur on its own. It is sent before a + * wl_touch.frame event and carries the new shape information for + * any previously reported, or new touch points of that frame. + * + * Other events describing the touch point such as wl_touch.down, + * wl_touch.motion or wl_touch.orientation may be sent within the + * same wl_touch.frame. A client should treat these events as a + * single logical touch point update. The order of wl_touch.shape, + * wl_touch.orientation and wl_touch.motion is not guaranteed. A + * wl_touch.down event is guaranteed to occur before the first + * wl_touch.shape event for this touch ID but both events may occur + * within the same wl_touch.frame. + * + * A touchpoint shape is approximated by an ellipse through the + * major and minor axis length. The major axis length describes the + * longer diameter of the ellipse, while the minor axis length + * describes the shorter diameter. Major and minor are orthogonal + * and both are specified in surface-local coordinates. The center + * of the ellipse is always at the touchpoint location as reported + * by wl_touch.down or wl_touch.move. + * + * This event is only sent by the compositor if the touch device + * supports shape reports. The client has to make reasonable + * assumptions about the shape if it did not receive this event. + * @param id the unique ID of this touch point + * @param major length of the major axis in surface-local coordinates + * @param minor length of the minor axis in surface-local coordinates + * @since 6 + */ + void (*shape)(void *data, + struct wl_touch *wl_touch, + int32_t id, + wl_fixed_t major, + wl_fixed_t minor); + /** + * update orientation of touch point + * + * Sent when a touchpoint has changed its orientation. + * + * This event does not occur on its own. It is sent before a + * wl_touch.frame event and carries the new shape information for + * any previously reported, or new touch points of that frame. + * + * Other events describing the touch point such as wl_touch.down, + * wl_touch.motion or wl_touch.shape may be sent within the same + * wl_touch.frame. A client should treat these events as a single + * logical touch point update. The order of wl_touch.shape, + * wl_touch.orientation and wl_touch.motion is not guaranteed. A + * wl_touch.down event is guaranteed to occur before the first + * wl_touch.orientation event for this touch ID but both events may + * occur within the same wl_touch.frame. + * + * The orientation describes the clockwise angle of a touchpoint's + * major axis to the positive surface y-axis and is normalized to + * the -180 to +180 degree range. The granularity of orientation + * depends on the touch device, some devices only support binary + * rotation values between 0 and 90 degrees. + * + * This event is only sent by the compositor if the touch device + * supports orientation reports. + * @param id the unique ID of this touch point + * @param orientation angle between major axis and positive surface y-axis in degrees + * @since 6 + */ + void (*orientation)(void *data, + struct wl_touch *wl_touch, + int32_t id, + wl_fixed_t orientation); }; /** @@ -4782,6 +4870,14 @@ wl_touch_add_listener(struct wl_touch *wl_touch, * @ingroup iface_wl_touch */ #define WL_TOUCH_CANCEL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_SHAPE_SINCE_VERSION 6 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 /** * @ingroup iface_wl_touch diff --git a/tests/data/example-code.c b/tests/data/example-code.c index 7dea253c..bc03fe56 100644 --- a/tests/data/example-code.c +++ b/tests/data/example-code.c @@ -383,7 +383,7 @@ static const struct wl_message wl_seat_events[] = { }; WL_EXPORT const struct wl_interface wl_seat_interface = { - "wl_seat", 5, + "wl_seat", 6, 4, wl_seat_requests, 2, wl_seat_events, }; @@ -406,7 +406,7 @@ static const struct wl_message wl_pointer_events[] = { }; WL_EXPORT const struct wl_interface wl_pointer_interface = { - "wl_pointer", 5, + "wl_pointer", 6, 2, wl_pointer_requests, 9, wl_pointer_events, }; @@ -425,7 +425,7 @@ static const struct wl_message wl_keyboard_events[] = { }; WL_EXPORT const struct wl_interface wl_keyboard_interface = { - "wl_keyboard", 5, + "wl_keyboard", 6, 1, wl_keyboard_requests, 6, wl_keyboard_events, }; @@ -440,12 +440,14 @@ static const struct wl_message wl_touch_events[] = { { "motion", "uiff", types + 0 }, { "frame", "", types + 0 }, { "cancel", "", types + 0 }, + { "shape", "6iff", types + 0 }, + { "orientation", "6if", types + 0 }, }; WL_EXPORT const struct wl_interface wl_touch_interface = { - "wl_touch", 5, + "wl_touch", 6, 1, wl_touch_requests, - 5, wl_touch_events, + 7, wl_touch_events, }; static const struct wl_message wl_output_requests[] = { diff --git a/tests/data/example-server.h b/tests/data/example-server.h index 22550f6c..f22f70fb 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -111,8 +111,8 @@ extern const struct wl_interface wl_display_interface; * @page page_iface_wl_registry wl_registry * @section page_iface_wl_registry_desc Description * - * The global registry object. The server has a number of global - * objects that are available to all clients. These objects + * The singleton global registry object. The server has a number of + * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. @@ -137,8 +137,8 @@ extern const struct wl_interface wl_display_interface; /** * @defgroup iface_wl_registry The wl_registry interface * - * The global registry object. The server has a number of global - * objects that are available to all clients. These objects + * The singleton global registry object. The server has a number of + * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. @@ -223,7 +223,7 @@ extern const struct wl_interface wl_shm_pool_interface; * @page page_iface_wl_shm wl_shm * @section page_iface_wl_shm_desc Description * - * A global singleton object that provides support for shared + * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool @@ -238,7 +238,7 @@ extern const struct wl_interface wl_shm_pool_interface; /** * @defgroup iface_wl_shm The wl_shm interface * - * A global singleton object that provides support for shared + * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool @@ -3247,7 +3247,7 @@ enum wl_pointer_axis { */ enum wl_pointer_axis_source { /** - * a physical wheel + * a physical wheel rotation */ WL_POINTER_AXIS_SOURCE_WHEEL = 0, /** @@ -3699,6 +3699,8 @@ struct wl_touch_interface { #define WL_TOUCH_MOTION 2 #define WL_TOUCH_FRAME 3 #define WL_TOUCH_CANCEL 4 +#define WL_TOUCH_SHAPE 5 +#define WL_TOUCH_ORIENTATION 6 /** * @ingroup iface_wl_touch @@ -3720,6 +3722,14 @@ struct wl_touch_interface { * @ingroup iface_wl_touch */ #define WL_TOUCH_CANCEL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_SHAPE_SINCE_VERSION 6 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 /** * @ingroup iface_wl_touch @@ -3794,6 +3804,33 @@ wl_touch_send_cancel(struct wl_resource *resource_) wl_resource_post_event(resource_, WL_TOUCH_CANCEL); } +/** + * @ingroup iface_wl_touch + * Sends an shape event to the client owning the resource. + * @param resource_ The client's resource + * @param id the unique ID of this touch point + * @param major length of the major axis in surface-local coordinates + * @param minor length of the minor axis in surface-local coordinates + */ +static inline void +wl_touch_send_shape(struct wl_resource *resource_, int32_t id, wl_fixed_t major, wl_fixed_t minor) +{ + wl_resource_post_event(resource_, WL_TOUCH_SHAPE, id, major, minor); +} + +/** + * @ingroup iface_wl_touch + * Sends an orientation event to the client owning the resource. + * @param resource_ The client's resource + * @param id the unique ID of this touch point + * @param orientation angle between major axis and positive surface y-axis in degrees + */ +static inline void +wl_touch_send_orientation(struct wl_resource *resource_, int32_t id, wl_fixed_t orientation) +{ + wl_resource_post_event(resource_, WL_TOUCH_ORIENTATION, id, orientation); +} + #ifndef WL_OUTPUT_SUBPIXEL_ENUM #define WL_OUTPUT_SUBPIXEL_ENUM /** diff --git a/tests/data/example.xml b/tests/data/example.xml index 6c6d078a..22dcffdc 100644 --- a/tests/data/example.xml +++ b/tests/data/example.xml @@ -104,8 +104,8 @@ - The global registry object. The server has a number of global - objects that are available to all clients. These objects + The singleton global registry object. The server has a number of + global objects that are available to all clients. These objects typically represent an actual object in the server (for example, an input device) or they are singleton objects that provide extension functionality. @@ -129,7 +129,7 @@ Binds a new, client-created object to the server using the - specified name as the identifier. + specified name as the identifier. @@ -139,9 +139,9 @@ Notify the client of global objects. - The event notifies the client that a global object with - the given name is now available, and it implements the - given version of the given interface. + The event notifies the client that a global object with + the given name is now available, and it implements the + given version of the given interface. @@ -152,10 +152,10 @@ Notify the client of removed global objects. - This event notifies the client that the global identified - by name is no longer available. If the client bound to - the global using the bind request, the client should now - destroy that object. + This event notifies the client that the global identified + by name is no longer available. If the client bound to + the global using the bind request, the client should now + destroy that object. The object remains valid and requests to the object will be ignored until the client destroys it, to avoid races between @@ -226,7 +226,6 @@ so it is valid to destroy the pool immediately after creating a buffer from it. - @@ -252,14 +251,13 @@ created, but using the new size. This request can only be used to make the pool bigger. -
- A global singleton object that provides support for shared + A singleton global object that provides support for shared memory. Clients can create wl_shm_pool objects using the create_pool @@ -357,9 +355,8 @@ The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file - descriptor, to use as backing memory for the pool. + descriptor, to use as backing memory for the pool. - @@ -449,7 +446,6 @@ wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback. - @@ -487,7 +483,6 @@ Sent immediately after creating the wl_data_offer object. One event per offered mime type. - @@ -635,7 +630,6 @@ Used for feedback during drag-and-drop. - @@ -645,7 +639,6 @@ specified mime type over the passed file descriptor, then close it. - @@ -823,7 +816,6 @@ object will send out data_offer.offer events to describe the mime types it offers. - @@ -834,7 +826,6 @@ enter time is provided by the x and y arguments, in surface-local coordinates. - @@ -924,14 +915,14 @@ - Create a new data source. + Create a new data source. - Create a new data device for a given seat. + Create a new data device for a given seat. @@ -1090,7 +1081,6 @@ The flags argument controls details of the transient behaviour. - @@ -1173,7 +1163,6 @@ corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. - @@ -1260,7 +1249,6 @@ The width and height arguments specify the size of the window in surface-local coordinates. - @@ -1320,7 +1308,7 @@ - These errors can be emitted in response to wl_surface requests. + These errors can be emitted in response to wl_surface requests. @@ -1374,7 +1362,6 @@ If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. - @@ -1405,7 +1392,6 @@ which uses buffer coordinates instead of surface coordinates, and is probably the preferred and intuitive way of doing this. - @@ -1447,7 +1433,6 @@ The callback_data passed in the callback is the current time, in milliseconds, with an undefined base. - @@ -1478,7 +1463,6 @@ destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty. - @@ -1508,7 +1492,6 @@ immediately. A NULL wl_region causes the input region to be set to infinite. - @@ -1661,7 +1644,6 @@ two requests separately and only transform from one to the other after receiving the wl_surface.commit. - @@ -1669,7 +1651,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -1679,8 +1661,8 @@ - This is a bitmask of capabilities this seat has; if a member is - set, then it is present on the seat. + This is a bitmask of capabilities this seat has; if a member is + set, then it is present on the seat. @@ -1778,7 +1760,7 @@ - + The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -1828,7 +1810,6 @@ cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. - @@ -1845,7 +1826,6 @@ is undefined and a client should respond to this event by setting an appropriate pointer image with the set_cursor request. - @@ -1870,7 +1850,6 @@ surface_x and surface_y are the location relative to the focused surface. - @@ -1878,7 +1857,7 @@ - Describes the physical state of a button that produced the button + Describes the physical state of a button that produced the button event. @@ -1891,10 +1870,17 @@ The location of the click is given by the last motion or enter event. - The time argument is a timestamp with millisecond - granularity, with an undefined base. - + The time argument is a timestamp with millisecond + granularity, with an undefined base. + The button is a button code as defined in the Linux kernel's + linux/input-event-codes.h header file, e.g. BTN_LEFT. + + Any 16-bit button code value is reserved for future additions to the + kernel's event code list. All other button codes above 0xFFFF are + currently undefined but may be used in future versions of this + protocol. + @@ -1928,7 +1914,6 @@ When applicable, a client can transform its content relative to the scroll distance. - @@ -2002,7 +1987,7 @@ the vertical motion of a device is converted to scroll events while a button is held down. - + @@ -2092,7 +2077,7 @@ - + The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -2106,7 +2091,7 @@ + summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/> @@ -2152,10 +2137,9 @@ A key was pressed or released. - The time argument is a timestamp with millisecond - granularity, with an undefined base. + The time argument is a timestamp with millisecond + granularity, with an undefined base. - @@ -2167,7 +2151,6 @@ Notifies clients that the modifier and/or group state has changed, and it should update its local state. - @@ -2185,28 +2168,27 @@ - Informs the client about the keyboard's repeat rate and delay. + Informs the client about the keyboard's repeat rate and delay. - This event is sent as soon as the wl_keyboard object has been created, - and is guaranteed to be received by the client before any key press - event. + This event is sent as soon as the wl_keyboard object has been created, + and is guaranteed to be received by the client before any key press + event. - Negative values for either rate or delay are illegal. A rate of zero - will disable any repeating (regardless of the value of delay). + Negative values for either rate or delay are illegal. A rate of zero + will disable any repeating (regardless of the value of delay). - This event can be sent later on as well with a new value if necessary, - so clients should continue listening for the event past the creation - of wl_keyboard. + This event can be sent later on as well with a new value if necessary, + so clients should continue listening for the event past the creation + of wl_keyboard. - + summary="the rate of repeating keys in characters per second"/> + summary="delay in milliseconds since key down until repeating starts"/> - + The wl_touch interface represents a touchscreen associated with a seat. @@ -2256,7 +2238,14 @@ - Indicates the end of a contact point list. + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. + + A wl_touch.frame terminates at least one event but otherwise no + guarantee is provided about the set of events within a frame. A client + must assume that any state not updated in a frame is unchanged from the + previously known state. @@ -2276,6 +2265,71 @@ + + + + + + Sent when a touchpoint has changed its shape. + + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. + + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.orientation may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.shape event for this touch ID but both events may occur within + the same wl_touch.frame. + + A touchpoint shape is approximated by an ellipse through the major and + minor axis length. The major axis length describes the longer diameter + of the ellipse, while the minor axis length describes the shorter + diameter. Major and minor are orthogonal and both are specified in + surface-local coordinates. The center of the ellipse is always at the + touchpoint location as reported by wl_touch.down or wl_touch.move. + + This event is only sent by the compositor if the touch device supports + shape reports. The client has to make reasonable assumptions about the + shape if it did not receive this event. + + + + + + + + + Sent when a touchpoint has changed its orientation. + + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. + + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.shape may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.orientation event for this touch ID but both events may occur + within the same wl_touch.frame. + + The orientation describes the clockwise angle of a touchpoint's major + axis to the positive surface y-axis and is normalized to the -180 to + +180 degree range. The granularity of orientation depends on the touch + device, some devices only support binary rotation values between 0 and + 90 degrees. + + This event is only sent by the compositor if the touch device supports + orientation reports. + + + + @@ -2315,7 +2369,6 @@ compositor will still be able to scan out directly from client surfaces. - @@ -2372,10 +2425,10 @@ mode that was received with the current flag set. The size of a mode is given in physical hardware units of - the output device. This is not necessarily the same as - the output size in the global compositor space. For instance, - the output may be scaled, as described in wl_output.scale, - or transformed, as described in wl_output.transform. + the output device. This is not necessarily the same as + the output size in the global compositor space. For instance, + the output may be scaled, as described in wl_output.scale, + or transformed, as described in wl_output.transform. @@ -2387,20 +2440,20 @@ - This event is sent after all other properties have been - sent after binding to the output object and after any - other property changes done after that. This allows - changes to the output properties to be seen as - atomic, even if they happen via multiple events. + This event is sent after all other properties have been + sent after binding to the output object and after any + other property changes done after that. This allows + changes to the output properties to be seen as + atomic, even if they happen via multiple events. This event contains scaling geometry information - that is not in the geometry event. It may be sent after - binding the output object or if the output scale changes - later. If it is not sent, the client should assume a + that is not in the geometry event. It may be sent after + binding the output object or if the output scale changes + later. If it is not sent, the client should assume a scale of 1. A scale larger than 1 means that the compositor will @@ -2447,7 +2500,6 @@ Add the specified rectangle to the region. - @@ -2458,7 +2510,6 @@ Subtract the specified rectangle from the region. - @@ -2499,7 +2550,7 @@ + summary="the to-be sub-surface is invalid"/> @@ -2512,13 +2563,12 @@ must not have an existing wl_subsurface object. Otherwise a protocol error is raised. - + summary="the new sub-surface object ID"/> + summary="the surface to be turned into a sub-surface"/> + summary="the parent surface"/> @@ -2587,7 +2637,7 @@ + summary="wl_surface is not a sibling or the parent"/> @@ -2609,7 +2659,6 @@ The initial position is 0, 0. - @@ -2632,9 +2681,8 @@ A new sub-surface is initially added as the top-most in the stack of its siblings and parent. - + summary="the reference surface"/> @@ -2642,9 +2690,8 @@ The sub-surface is placed just below the reference surface. See wl_subsurface.place_above. - + summary="the reference surface"/> From 6c481003a2e971c59d3e2fc758d50bb4d623f2bd Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 24 Jan 2017 09:56:37 +1000 Subject: [PATCH 0410/1152] scanner: add helper function to convert "since" to a version Same code we already had, just moved into a helper function Signed-off-by: Peter Hutterer Reviewed-by: Yong Bakos Reviewed-by: Daniel Stone Reviewed-by: Pekka Paalanen --- src/scanner.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index a239c711..5d66fa48 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -609,6 +609,27 @@ strtouint(const char *str) return (int)ret; } +static int +version_from_since(struct parse_context *ctx, const char *since) +{ + int version; + + if (since != NULL) { + version = strtouint(since); + if (version == -1) { + fail(&ctx->loc, "invalid integer (%s)\n", since); + } else if (version > ctx->interface->version) { + fail(&ctx->loc, "since (%u) larger than version (%u)\n", + version, ctx->interface->version); + } + } else { + version = 1; + } + + + return version; +} + static void start_element(void *data, const char *element_name, const char **atts) { @@ -694,17 +715,7 @@ start_element(void *data, const char *element_name, const char **atts) if (type != NULL && strcmp(type, "destructor") == 0) message->destructor = 1; - if (since != NULL) { - version = strtouint(since); - if (version == -1) { - fail(&ctx->loc, "invalid integer (%s)\n", since); - } else if (version > ctx->interface->version) { - fail(&ctx->loc, "since (%u) larger than version (%u)\n", - version, ctx->interface->version); - } - } else { - version = 1; - } + version = version_from_since(ctx, since); if (version < ctx->interface->since) warn(&ctx->loc, "since version not increasing\n"); From f8ab47690c03245da4938cbab7a4ba6bcb1bebe0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 24 Jan 2017 09:56:38 +1000 Subject: [PATCH 0411/1152] scanner: support "since" attribute for enum entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was already in the DTD but not supported by the scanner. The check for ever-increasing "since" tags is not strictly required for enum entries as we control the binary value. But it keeps the xml file in good order, preventing things like: If this is undesirable in the future the check can be removed without side-effects. Signed-off-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- src/scanner.c | 34 ++++++++++++++++++++++++++++++---- tests/data/small-client-core.h | 23 +++++++++++++++++++++++ tests/data/small-client.h | 23 +++++++++++++++++++++++ tests/data/small-code-core.c | 2 +- tests/data/small-code.c | 2 +- tests/data/small-server-core.h | 23 +++++++++++++++++++++++ tests/data/small-server.h | 23 +++++++++++++++++++++++ tests/data/small.xml | 8 +++++++- 8 files changed, 131 insertions(+), 7 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 5d66fa48..a6c334fb 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -213,6 +213,7 @@ struct enumeration { struct wl_list link; struct description *description; bool bitfield; + int since; }; struct entry { @@ -220,6 +221,7 @@ struct entry { char *uppercase_name; char *value; char *summary; + int since; struct wl_list link; }; @@ -494,6 +496,7 @@ create_enumeration(const char *name) enumeration = xzalloc(sizeof *enumeration); enumeration->name = xstrdup(name); enumeration->uppercase_name = uppercase_dup(name); + enumeration->since = 1; wl_list_init(&enumeration->entry_list); @@ -797,6 +800,12 @@ start_element(void *data, const char *element_name, const char **atts) fail(&ctx->loc, "no entry name given"); entry = create_entry(name, value); + version = version_from_since(ctx, since); + + if (version < ctx->enumeration->since) + warn(&ctx->loc, "since version not increasing\n"); + ctx->enumeration->since = version; + entry->since = version; if (summary) entry->summary = xstrdup(summary); @@ -1278,16 +1287,33 @@ emit_enumerations(struct interface *interface) } printf("enum %s_%s {\n", interface->name, e->name); wl_list_for_each(entry, &e->entry_list, link) { - if (entry->summary) - printf("\t/**\n" - "\t * %s\n" - "\t */\n", entry->summary); + if (entry->summary || entry->since > 1) { + printf("\t/**\n"); + if (entry->summary) + printf("\t * %s\n", entry->summary); + if (entry->since > 1) + printf("\t * @since %d\n", entry->since); + printf("\t */\n"); + } printf("\t%s_%s_%s = %s,\n", interface->uppercase_name, e->uppercase_name, entry->uppercase_name, entry->value); } printf("};\n"); + + wl_list_for_each(entry, &e->entry_list, link) { + if (entry->since == 1) + continue; + + printf("/**\n * @ingroup iface_%s\n */\n", interface->name); + printf("#define %s_%s_%s_SINCE_VERSION %d\n", + interface->uppercase_name, + e->uppercase_name, entry->uppercase_name, + entry->since); + + } + printf("#endif /* %s_%s_ENUM */\n\n", interface->uppercase_name, e->uppercase_name); } diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h index 8d02edb7..c85cca60 100644 --- a/tests/data/small-client-core.h +++ b/tests/data/small-client-core.h @@ -61,6 +61,29 @@ struct intf_not_here; */ extern const struct wl_interface intf_A_interface; +#ifndef INTF_A_FOO_ENUM +#define INTF_A_FOO_ENUM +enum intf_A_foo { + /** + * this is the first + */ + INTF_A_FOO_FIRST = 0, + /** + * this is the second + */ + INTF_A_FOO_SECOND = 1, + /** + * this is the third + * @since 2 + */ + INTF_A_FOO_THIRD = 2, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_FOO_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_listener diff --git a/tests/data/small-client.h b/tests/data/small-client.h index 050e63ff..884346d5 100644 --- a/tests/data/small-client.h +++ b/tests/data/small-client.h @@ -61,6 +61,29 @@ struct intf_not_here; */ extern const struct wl_interface intf_A_interface; +#ifndef INTF_A_FOO_ENUM +#define INTF_A_FOO_ENUM +enum intf_A_foo { + /** + * this is the first + */ + INTF_A_FOO_FIRST = 0, + /** + * this is the second + */ + INTF_A_FOO_SECOND = 1, + /** + * this is the third + * @since 2 + */ + INTF_A_FOO_THIRD = 2, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_FOO_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_listener diff --git a/tests/data/small-code-core.c b/tests/data/small-code-core.c index dbf7f401..28a00ab9 100644 --- a/tests/data/small-code-core.c +++ b/tests/data/small-code-core.c @@ -54,7 +54,7 @@ static const struct wl_message intf_A_events[] = { }; WL_EXPORT const struct wl_interface intf_A_interface = { - "intf_A", 1, + "intf_A", 3, 3, intf_A_requests, 1, intf_A_events, }; diff --git a/tests/data/small-code.c b/tests/data/small-code.c index dbf7f401..28a00ab9 100644 --- a/tests/data/small-code.c +++ b/tests/data/small-code.c @@ -54,7 +54,7 @@ static const struct wl_message intf_A_events[] = { }; WL_EXPORT const struct wl_interface intf_A_interface = { - "intf_A", 1, + "intf_A", 3, 3, intf_A_requests, 1, intf_A_events, }; diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h index c1e8d05a..6dd2d05a 100644 --- a/tests/data/small-server-core.h +++ b/tests/data/small-server-core.h @@ -64,6 +64,29 @@ struct intf_not_here; */ extern const struct wl_interface intf_A_interface; +#ifndef INTF_A_FOO_ENUM +#define INTF_A_FOO_ENUM +enum intf_A_foo { + /** + * this is the first + */ + INTF_A_FOO_FIRST = 0, + /** + * this is the second + */ + INTF_A_FOO_SECOND = 1, + /** + * this is the third + * @since 2 + */ + INTF_A_FOO_THIRD = 2, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_FOO_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_interface diff --git a/tests/data/small-server.h b/tests/data/small-server.h index 0bd8a1d9..4763f5bb 100644 --- a/tests/data/small-server.h +++ b/tests/data/small-server.h @@ -64,6 +64,29 @@ struct intf_not_here; */ extern const struct wl_interface intf_A_interface; +#ifndef INTF_A_FOO_ENUM +#define INTF_A_FOO_ENUM +enum intf_A_foo { + /** + * this is the first + */ + INTF_A_FOO_FIRST = 0, + /** + * this is the second + */ + INTF_A_FOO_SECOND = 1, + /** + * this is the third + * @since 2 + */ + INTF_A_FOO_THIRD = 2, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_FOO_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_interface diff --git a/tests/data/small.xml b/tests/data/small.xml index 571618f1..a6e62ad8 100644 --- a/tests/data/small.xml +++ b/tests/data/small.xml @@ -26,7 +26,7 @@ SOFTWARE. - + A useless example trying to tickle the scanner. @@ -48,5 +48,11 @@ + + + + + + From 2f72d0a8a82dac8c961cb9b4b509208b84322937 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 24 Jan 2017 09:56:39 +1000 Subject: [PATCH 0412/1152] protocol: add axis_source.wheel_tilt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike a wheel rotation, a wheel tilt is a discrete-only axis. Wheel rotations are mapped to degrees in libinput but that that does not apply to wheel tilt axes where there is no physical equivalent. Signed-off-by: Peter Hutterer Reviewed-by: Jonas Ådahl Acked-by: Daniel Stone Reviewed-by: Daniel Stone Reviewed-by: Yong Bakos --- protocol/wayland.xml | 10 ++++++++-- tests/data/example-client.h | 16 +++++++++++++++- tests/data/example-server.h | 13 +++++++++++++ tests/data/example.xml | 8 +++++++- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 098f286b..29b63be7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1986,10 +1986,15 @@ finger. One example for this source is button-based scrolling where the vertical motion of a device is converted to scroll events while a button is held down. + + The "wheel tilt" axis source indicates that the actual device is a + wheel but the scroll event is not caused by a rotation but a + (usually sideways) tilt of the wheel. - + + @@ -2004,7 +2009,8 @@ wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be sent when the user lifts the finger off the device. - If the source is wl_pointer axis_source.wheel or + If the source is wl_pointer.axis_source.wheel, + wl_pointer.axis_source.wheel_tilt or wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may or may not be sent. Whether a compositor sends an axis_stop event for these sources is hardware-specific and implementation-dependent; diff --git a/tests/data/example-client.h b/tests/data/example-client.h index 857aacfe..c40e3611 100644 --- a/tests/data/example-client.h +++ b/tests/data/example-client.h @@ -4035,6 +4035,10 @@ enum wl_pointer_axis { * finger. One example for this source is button-based scrolling where * the vertical motion of a device is converted to scroll events while * a button is held down. + * + * The "wheel tilt" axis source indicates that the actual device is a + * wheel but the scroll event is not caused by a rotation but a + * (usually sideways) tilt of the wheel. */ enum wl_pointer_axis_source { /** @@ -4049,7 +4053,16 @@ enum wl_pointer_axis_source { * continuous coordinate space */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, + /** + * a physical wheel tilt + * @since 6 + */ + WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, }; +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 #endif /* WL_POINTER_AXIS_SOURCE_ENUM */ /** @@ -4216,7 +4229,8 @@ struct wl_pointer_listener { * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event * will be sent when the user lifts the finger off the device. * - * If the source is wl_pointer axis_source.wheel or + * If the source is wl_pointer.axis_source.wheel, + * wl_pointer.axis_source.wheel_tilt or * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event * may or may not be sent. Whether a compositor sends an axis_stop * event for these sources is hardware-specific and diff --git a/tests/data/example-server.h b/tests/data/example-server.h index f22f70fb..adfc973c 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -3244,6 +3244,10 @@ enum wl_pointer_axis { * finger. One example for this source is button-based scrolling where * the vertical motion of a device is converted to scroll events while * a button is held down. + * + * The "wheel tilt" axis source indicates that the actual device is a + * wheel but the scroll event is not caused by a rotation but a + * (usually sideways) tilt of the wheel. */ enum wl_pointer_axis_source { /** @@ -3258,7 +3262,16 @@ enum wl_pointer_axis_source { * continuous coordinate space */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, + /** + * a physical wheel tilt + * @since 6 + */ + WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, }; +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 #endif /* WL_POINTER_AXIS_SOURCE_ENUM */ /** diff --git a/tests/data/example.xml b/tests/data/example.xml index 22dcffdc..29b63be7 100644 --- a/tests/data/example.xml +++ b/tests/data/example.xml @@ -1986,10 +1986,15 @@ finger. One example for this source is button-based scrolling where the vertical motion of a device is converted to scroll events while a button is held down. + + The "wheel tilt" axis source indicates that the actual device is a + wheel but the scroll event is not caused by a rotation but a + (usually sideways) tilt of the wheel. + @@ -2004,7 +2009,8 @@ wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be sent when the user lifts the finger off the device. - If the source is wl_pointer axis_source.wheel or + If the source is wl_pointer.axis_source.wheel, + wl_pointer.axis_source.wheel_tilt or wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may or may not be sent. Whether a compositor sends an axis_stop event for these sources is hardware-specific and implementation-dependent; From d915447365be68a39607a176e03e06a05cb8a72d Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 18 Oct 2016 16:23:39 +0200 Subject: [PATCH 0413/1152] wayland-server: Add API to control globals visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new API to let compositor decide whether or not a wl_global should be advertised to the clients via wl_registry_bind() or display_get_registry() By using its own filter, the compositor can decide which wl_global would be listed to clients. Compositors can use this mechanism to hide their own private interfaces that regular clients should not use. - Hiding interfaces that expose compositor implementation details makes it harder for clients to identify the compositor. Therefore clients are a little less likely to develop compositor-specific workarounds instead of reporting problems upstream. - Hiding can be used to diminish the problems from missing namespacing: if two compositors happen to use the same named global with different interfaces for their special-purpose clients, the client expecting the different interface would probably never see it advertised. Signed-off-by: Olivier Fourdan Reviewed-by: Jonas Ådahl Reviewed-by: Yong Bakos Acked-by: Pekka Paalanen Reviewed-by: Pekka Paalanen --- src/wayland-server-core.h | 25 +++++++++++++++ src/wayland-server.c | 67 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 2c215e4c..9ae51dc4 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -28,6 +28,7 @@ #include #include +#include #include "wayland-util.h" #include "wayland-version.h" @@ -168,6 +169,30 @@ wl_global_create(struct wl_display *display, void wl_global_destroy(struct wl_global *global); +/** A filter function for wl_global objects + * + * \param client The client object + * \param global The global object to show or hide + * \param data The user data pointer + * + * A filter function enables the server to decide which globals to + * advertise to each client. + * + * When a wl_global filter is set, the given callback funtion will be + * called during wl_global advertisment and binding. + * + * This function should return true if the global object should be made + * visible to the client or false otherwise. + */ +typedef bool (*wl_display_global_filter_func_t)(const struct wl_client *client, + const struct wl_global *global, + void *data); + +void +wl_display_set_global_filter(struct wl_display *display, + wl_display_global_filter_func_t filter, + void *data); + struct wl_client * wl_client_create(struct wl_display *display, int fd); diff --git a/src/wayland-server.c b/src/wayland-server.c index 9d7d9c1b..893bb563 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -101,6 +101,9 @@ struct wl_display { struct wl_signal create_client_signal; struct wl_array additional_shm_formats; + + wl_display_global_filter_func_t global_filter; + void *global_filter_data; }; struct wl_global { @@ -769,6 +772,21 @@ wl_client_destroy(struct wl_client *client) free(client); } +/* Check if a global filter is registered and use it if any. + * + * If no wl_global filter has been registered, this funtion will + * return true, allowing the wl_global to be visible to the wl_client + */ +static bool +wl_global_is_visible(const struct wl_client *client, + const struct wl_global *global) +{ + struct wl_display *display = client->display; + + return (display->global_filter == NULL || + display->global_filter(client, global, display->global_filter_data)); +} + static void registry_bind(struct wl_client *client, struct wl_resource *resource, uint32_t name, @@ -795,6 +813,10 @@ registry_bind(struct wl_client *client, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid version for global %s (%d): have %d, wanted %d", interface, name, global->version, version); + else if (!wl_global_is_visible(client, global)) + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid global %s (%d)", interface, name); else global->bind(client, global->data, version, id); } @@ -850,11 +872,12 @@ display_get_registry(struct wl_client *client, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) - wl_resource_post_event(registry_resource, - WL_REGISTRY_GLOBAL, - global->name, - global->interface->name, - global->version); + if (wl_global_is_visible(client, global)) + wl_resource_post_event(registry_resource, + WL_REGISTRY_GLOBAL, + global->name, + global->interface->name, + global->version); } static const struct wl_display_interface display_interface = { @@ -925,6 +948,9 @@ wl_display_create(void) display->id = 1; display->serial = 0; + display->global_filter = NULL; + display->global_filter_data = NULL; + wl_array_init(&display->additional_shm_formats); return display; @@ -999,6 +1025,37 @@ wl_display_destroy(struct wl_display *display) free(display); } +/** Set a filter function for global objects + * + * \param display The Wayland display object. + * \param filter The global filter funtion. + * \param data User data to be associated with the global filter. + * \return None. + * + * Set a filter for the wl_display to advertise or hide global objects + * to clients. + * The set filter will be used during wl_global advertisment to + * determine whether a global object should be advertised to a + * given client, and during wl_global binding to determine whether + * a given client should be allowed to bind to a global. + * + * Clients that try to bind to a global that was filtered out will + * have an error raised. + * + * Setting the filter NULL will result in all globals being + * advertised to all clients. The default is no filter. + * + * \memberof wl_display + */ +WL_EXPORT void +wl_display_set_global_filter(struct wl_display *display, + wl_display_global_filter_func_t filter, + void *data) +{ + display->global_filter = filter; + display->global_filter_data = data; +} + WL_EXPORT struct wl_global * wl_global_create(struct wl_display *display, const struct wl_interface *interface, int version, From 65b773e51fe874c78785fe3e63a8d6972fa0c57c Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 18 Oct 2016 16:23:40 +0200 Subject: [PATCH 0414/1152] wayland-server: Add functions to wl_global When using a wl_global, a server may need to retrieve the associated wl_interface and user data. Add a couple of convenient functions wl_global_get_interface() and wl_global_get_user_data() for this purpose. Signed-off-by: Olivier Fourdan Reviewed-by: Yong Bakos Reviewed-by: Pekka Paalanen --- src/wayland-server-core.h | 6 ++++++ src/wayland-server.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 9ae51dc4..61da8ab7 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -193,6 +193,12 @@ wl_display_set_global_filter(struct wl_display *display, wl_display_global_filter_func_t filter, void *data); +const struct wl_interface * +wl_global_get_interface(const struct wl_global *global); + +void * +wl_global_get_user_data(const struct wl_global *global); + struct wl_client * wl_client_create(struct wl_display *display, int fd); diff --git a/src/wayland-server.c b/src/wayland-server.c index 893bb563..43608744 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1113,6 +1113,18 @@ wl_global_destroy(struct wl_global *global) free(global); } +WL_EXPORT const struct wl_interface * +wl_global_get_interface(const struct wl_global *global) +{ + return global->interface; +} + +WL_EXPORT void * +wl_global_get_user_data(const struct wl_global *global) +{ + return global->data; +} + /** Get the current serial number * * \param display The display object From ad4f04872a3f99eaef38cceab1987906b0e19996 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 24 Jan 2017 18:13:26 -0800 Subject: [PATCH 0415/1152] configure.ac: bump to version 1.12.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6cda418d..7520b242 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [12]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 23d8bc5a64312d4e1e233fd04844cc22a6bb512d Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 24 Jan 2017 16:54:04 +0100 Subject: [PATCH 0416/1152] tests: Add a test for global filter Test if the global filter is effectively filtering out the global when the filter returns false. Signed-off-by: Olivier Fourdan --- tests/display-test.c | 140 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index 0c4df169..e6f03693 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -36,6 +36,8 @@ #include #include #include +#include + #include #include @@ -926,3 +928,141 @@ TEST(error_on_destroyed_object) display_resume(d); display_destroy(d); } + +static bool +global_filter(const struct wl_client *client, + const struct wl_global *global, + void *data) +{ + /* Hide the wl_data_offer interface if no data was provided */ + if (wl_global_get_interface(global) == &wl_data_offer_interface) + return data != NULL; + + /* Show all the others */ + return true; +} + +static void +bind_data_offer(struct wl_client *client, void *data, + uint32_t vers, uint32_t id) +{ + /* Client should not be able to bind to this interface! */ + assert(false); +} + +static void +registry_handle_filtered(void *data, struct wl_registry *registry, + uint32_t id, const char *intf, uint32_t ver) +{ + uint32_t *name = data; + + if (strcmp (intf, "wl_data_offer") == 0) { + assert(name); + *name = id; + } +} + +static const struct wl_registry_listener registry_listener_filtered = { + registry_handle_filtered, + NULL +}; + +static void +get_globals(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, ®istry_listener_filtered, data); + wl_display_roundtrip(c->wl_display); + + wl_registry_destroy(registry); + client_disconnect_nocheck(c); +} + +TEST(filtered_global_is_hidden) +{ + struct display *d; + struct wl_global *g; + + d = display_create(); + + g = wl_global_create(d->wl_display, &wl_data_offer_interface, + 1, d, bind_data_offer); + wl_display_set_global_filter(d->wl_display, global_filter, NULL); + + client_create_noarg(d, get_globals); + display_run(d); + + wl_global_destroy(g); + + display_destroy(d); +} + +static void +check_bind_error(struct client *c) +{ + uint32_t errorcode, id; + int err; + const struct wl_interface *intf; + + err = wl_display_get_error(c->wl_display); + assert(err == EPROTO); + + errorcode = wl_display_get_protocol_error(c->wl_display, &intf, &id); + assert(errorcode == WL_DISPLAY_ERROR_INVALID_OBJECT); +} + +static void +force_bind(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + void *ptr; + uint32_t *name = data; + + registry = wl_display_get_registry(c->wl_display); + + ptr = wl_registry_bind (registry, *name, &wl_data_offer_interface, 1); + wl_display_roundtrip(c->wl_display); + check_bind_error(c); + + wl_proxy_destroy((struct wl_proxy *) ptr); + wl_registry_destroy(registry); + + client_disconnect_nocheck(c); +} + +TEST(bind_fails_on_filtered_global) +{ + struct display *d; + struct wl_global *g; + uint32_t *name; + + /* Create a anonymous shared memory to pass the interface name */ + name = mmap(NULL, sizeof(uint32_t), + PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); + + d = display_create(); + + g = wl_global_create(d->wl_display, &wl_data_offer_interface, + 1, d, bind_data_offer); + wl_display_set_global_filter(d->wl_display, global_filter, name); + + client_create(d, get_globals, name); + *name = 0; + + display_run(d); + /* wl_data_offer should be 2 */ + assert(*name == 2); + wl_display_set_global_filter(d->wl_display, global_filter, NULL); + + /* Try to bind to the interface name when a global filter is in place */ + client_create(d, force_bind, name); + display_run(d); + + wl_global_destroy(g); + + display_destroy(d); +} From 5e6eb032294ecdee889600c604dfcaab0ffb9398 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Tue, 24 Jan 2017 16:34:28 +0200 Subject: [PATCH 0417/1152] server: add a safer signal type and port wl_display to it wl_list_for_each_safe, which is used by wl_signal_emit is not really safe. If a signal has two listeners, and the first one removes and re-inits the second one, it would enter an infinite loop, which was hit in weston on resource destruction, which emits a signal. This commit adds a new version of wl_signal, called wl_priv_signal, which is private in wayland-server.c and which does not have this problem. The old wl_signal cannot be improved without breaking backwards compatibility. Signed-off-by: Giulio Camuffo Reviewed-by: Pekka Paalanen --- Makefile.am | 4 + src/wayland-private.h | 18 +++ src/wayland-server.c | 109 +++++++++++-- tests/newsignal-test.c | 337 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 459 insertions(+), 9 deletions(-) create mode 100644 tests/newsignal-test.c diff --git a/Makefile.am b/Makefile.am index d78a0ca5..d0c8bd3e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -159,6 +159,7 @@ built_test_programs = \ socket-test \ queue-test \ signal-test \ + newsignal-test \ resources-test \ message-test \ headers-test \ @@ -226,6 +227,9 @@ queue_test_SOURCES = tests/queue-test.c queue_test_LDADD = libtest-runner.la signal_test_SOURCES = tests/signal-test.c signal_test_LDADD = libtest-runner.la +# wayland-server.c is needed here to access wl_priv_* functions +newsignal_test_SOURCES = tests/newsignal-test.c src/wayland-server.c +newsignal_test_LDADD = libtest-runner.la resources_test_SOURCES = tests/resources-test.c resources_test_LDADD = libtest-runner.la message_test_SOURCES = tests/message-test.c diff --git a/src/wayland-private.h b/src/wayland-private.h index 676b1813..434cb04e 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -35,6 +35,7 @@ #define WL_HIDE_DEPRECATED 1 #include "wayland-util.h" +#include "wayland-server-core.h" /* Invalid memory address */ #define WL_ARRAY_POISON_PTR (void *) 4 @@ -233,4 +234,21 @@ zalloc(size_t s) return calloc(1, s); } +struct wl_priv_signal { + struct wl_list listener_list; + struct wl_list emit_list; +}; + +void +wl_priv_signal_init(struct wl_priv_signal *signal); + +void +wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener); + +struct wl_listener * +wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify); + +void +wl_priv_signal_emit(struct wl_priv_signal *signal, void *data); + #endif diff --git a/src/wayland-server.c b/src/wayland-server.c index 43608744..1482d5e7 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -97,8 +97,8 @@ struct wl_display { struct wl_list client_list; struct wl_list protocol_loggers; - struct wl_signal destroy_signal; - struct wl_signal create_client_signal; + struct wl_priv_signal destroy_signal; + struct wl_priv_signal create_client_signal; struct wl_array additional_shm_formats; @@ -489,7 +489,7 @@ wl_client_create(struct wl_display *display, int fd) wl_list_insert(display->client_list.prev, &client->link); - wl_signal_emit(&display->create_client_signal, client); + wl_priv_signal_emit(&display->create_client_signal, client); return client; @@ -942,8 +942,8 @@ wl_display_create(void) wl_list_init(&display->registry_resource_list); wl_list_init(&display->protocol_loggers); - wl_signal_init(&display->destroy_signal); - wl_signal_init(&display->create_client_signal); + wl_priv_signal_init(&display->destroy_signal); + wl_priv_signal_init(&display->create_client_signal); display->id = 1; display->serial = 0; @@ -1008,7 +1008,7 @@ wl_display_destroy(struct wl_display *display) struct wl_socket *s, *next; struct wl_global *global, *gnext; - wl_signal_emit(&display->destroy_signal, display); + wl_priv_signal_emit(&display->destroy_signal, display); wl_list_for_each_safe(s, next, &display->socket_list, link) { wl_socket_destroy(s); @@ -1478,7 +1478,7 @@ WL_EXPORT void wl_display_add_destroy_listener(struct wl_display *display, struct wl_listener *listener) { - wl_signal_add(&display->destroy_signal, listener); + wl_priv_signal_add(&display->destroy_signal, listener); } /** Registers a listener for the client connection signal. @@ -1496,14 +1496,14 @@ WL_EXPORT void wl_display_add_client_created_listener(struct wl_display *display, struct wl_listener *listener) { - wl_signal_add(&display->create_client_signal, listener); + wl_priv_signal_add(&display->create_client_signal, listener); } WL_EXPORT struct wl_listener * wl_display_get_destroy_listener(struct wl_display *display, wl_notify_func_t notify) { - return wl_signal_get(&display->destroy_signal, notify); + return wl_priv_signal_get(&display->destroy_signal, notify); } WL_EXPORT void @@ -1812,6 +1812,97 @@ wl_client_for_each_resource(struct wl_client *client, wl_map_for_each(&client->objects, resource_iterator_helper, &context); } +/** Initialize a wl_priv_signal object + * + * wl_priv_signal is a safer implementation of a signal type, with the same API + * as wl_signal, but kept as a private utility of libwayland-server. + * It is safer because listeners can be removed from within wl_priv_signal_emit() + * without corrupting the signal's list. + * + * Before passing a wl_priv_signal object to any other function it must be + * initialized by useing wl_priv_signal_init(). + * + * \memberof wl_priv_signal + */ +void +wl_priv_signal_init(struct wl_priv_signal *signal) +{ + wl_list_init(&signal->listener_list); + wl_list_init(&signal->emit_list); +} + +/** Add a listener to a signal + * + * The new listener will be called when calling wl_signal_emit(). If a listener is + * added to the signal while wl_signal_emit() is running it will be called from + * the next time wl_priv_signal_emit() is called. + * To remove a listener call wl_list_remove() on its link member. + * + * \memberof wl_priv_signal + */ +void +wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener) +{ + wl_list_insert(signal->listener_list.prev, &listener->link); +} + +/** Get a listener added to a signal + * + * Returns the listener added to the given \a signal and with the given + * \a notify function, or NULL if there isn't any. + * Calling this function from withing wl_priv_signal_emit() is safe and will + * return the correct value. + * + * \memberof wl_priv_signal + */ +struct wl_listener * +wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify) +{ + struct wl_listener *l; + + wl_list_for_each(l, &signal->listener_list, link) + if (l->notify == notify) + return l; + wl_list_for_each(l, &signal->emit_list, link) + if (l->notify == notify) + return l; + + return NULL; +} + +/** Emit the signal, calling all the installed listeners + * + * Iterate over all the listeners added to this \a signal and call + * their \a notify function pointer, passing on the given \a data. + * Removing or adding a listener from within wl_priv_signal_emit() + * is safe. + */ +void +wl_priv_signal_emit(struct wl_priv_signal *signal, void *data) +{ + struct wl_listener *l; + struct wl_list *pos; + + wl_list_insert_list(&signal->emit_list, &signal->listener_list); + wl_list_init(&signal->listener_list); + + /* Take every element out of the list and put them in a temporary list. + * This way, the 'it' func can remove any element it wants from the list + * without troubles, because we always get the first element, not the + * one after the current, which may be invalid. + * wl_list_for_each_safe tries to be safe but it fails: it works fine + * if the current item is removed, but not if the next one is. */ + while (!wl_list_empty(&signal->emit_list)) { + pos = signal->emit_list.next; + l = wl_container_of(pos, l, link); + + wl_list_remove(pos); + wl_list_insert(&signal->listener_list, pos); + + l->notify(l, data); + } +} + /** \cond */ /* Deprecated functions below. */ uint32_t diff --git a/tests/newsignal-test.c b/tests/newsignal-test.c new file mode 100644 index 00000000..47c429bb --- /dev/null +++ b/tests/newsignal-test.c @@ -0,0 +1,337 @@ +/* + * Copyright © 2013 Marek Chalupa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "test-runner.h" +#include "wayland-private.h" + +static void +signal_notify(struct wl_listener *listener, void *data) +{ + /* only increase counter*/ + ++(*((int *) data)); +} + +TEST(signal_init) +{ + struct wl_priv_signal signal; + + wl_priv_signal_init(&signal); + + /* Test if listeners' list is initialized */ + assert(&signal.listener_list == signal.listener_list.next + && "Maybe wl_priv_signal implementation changed?"); + assert(signal.listener_list.next == signal.listener_list.prev + && "Maybe wl_priv_signal implementation changed?"); +} + +TEST(signal_add_get) +{ + struct wl_priv_signal signal; + + /* we just need different values of notify */ + struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1}; + struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2}; + struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3}; + /* one real, why not */ + struct wl_listener l4 = {.notify = signal_notify}; + + wl_priv_signal_init(&signal); + + wl_priv_signal_add(&signal, &l1); + wl_priv_signal_add(&signal, &l2); + wl_priv_signal_add(&signal, &l3); + wl_priv_signal_add(&signal, &l4); + + assert(wl_priv_signal_get(&signal, signal_notify) == &l4); + assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); + assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); + assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); + + /* get should not be destructive */ + assert(wl_priv_signal_get(&signal, signal_notify) == &l4); + assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); + assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); + assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); +} + +TEST(signal_emit_to_one_listener) +{ + int count = 0; + int counter; + + struct wl_priv_signal signal; + struct wl_listener l1 = {.notify = signal_notify}; + + wl_priv_signal_init(&signal); + wl_priv_signal_add(&signal, &l1); + + for (counter = 0; counter < 100; counter++) + wl_priv_signal_emit(&signal, &count); + + assert(counter == count); +} + +TEST(signal_emit_to_more_listeners) +{ + int count = 0; + int counter; + + struct wl_priv_signal signal; + struct wl_listener l1 = {.notify = signal_notify}; + struct wl_listener l2 = {.notify = signal_notify}; + struct wl_listener l3 = {.notify = signal_notify}; + + wl_priv_signal_init(&signal); + wl_priv_signal_add(&signal, &l1); + wl_priv_signal_add(&signal, &l2); + wl_priv_signal_add(&signal, &l3); + + for (counter = 0; counter < 100; counter++) + wl_priv_signal_emit(&signal, &count); + + assert(3 * counter == count); +} + +struct signal +{ + struct wl_priv_signal signal; + struct wl_listener l1, l2, l3; + int count; + struct wl_listener *current; +}; + +static void notify_remove(struct wl_listener *l, void *data) +{ + struct signal *sig = data; + wl_list_remove(&sig->current->link); + wl_list_init(&sig->current->link); + sig->count++; +} + +#define INIT \ + wl_priv_signal_init(&signal.signal); \ + wl_list_init(&signal.l1.link); \ + wl_list_init(&signal.l2.link); \ + wl_list_init(&signal.l3.link); +#define CHECK_EMIT(expected) \ + signal.count = 0; \ + wl_priv_signal_emit(&signal.signal, &signal); \ + assert(signal.count == expected); + +TEST(signal_remove_listener) +{ + test_set_timeout(4); + + struct signal signal; + + signal.l1.notify = notify_remove; + signal.l2.notify = notify_remove; + signal.l3.notify = notify_remove; + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + + signal.current = &signal.l1; + CHECK_EMIT(1) + CHECK_EMIT(0) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + + CHECK_EMIT(2) + CHECK_EMIT(1) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + + signal.current = &signal.l2; + CHECK_EMIT(1) + CHECK_EMIT(1) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + wl_priv_signal_add(&signal.signal, &signal.l3); + + signal.current = &signal.l1; + CHECK_EMIT(3) + CHECK_EMIT(2) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + wl_priv_signal_add(&signal.signal, &signal.l3); + + signal.current = &signal.l2; + CHECK_EMIT(2) + CHECK_EMIT(2) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + wl_priv_signal_add(&signal.signal, &signal.l3); + + signal.current = &signal.l3; + CHECK_EMIT(2) + CHECK_EMIT(2) +} + +static void notify_readd(struct wl_listener *l, void *data) +{ + struct signal *signal = data; + if (signal->current) { + wl_list_remove(&signal->current->link); + wl_list_init(&signal->current->link); + wl_priv_signal_add(&signal->signal, signal->current); + } + signal->count++; +} + +static void notify_empty(struct wl_listener *l, void *data) +{ + struct signal *signal = data; + signal->count++; +} + +TEST(signal_readd_listener) +{ + /* Readding a listener is supported, that is it doesn't trigger an + * infinite loop or other weird things, but if in a listener you + * readd another listener, that will not be fired in the current + * signal emission. */ + + test_set_timeout(4); + + struct signal signal; + + signal.l1.notify = notify_readd; + signal.l2.notify = notify_readd; + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + + signal.current = &signal.l1; + CHECK_EMIT(1) + CHECK_EMIT(1) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + + signal.current = &signal.l2; + CHECK_EMIT(1) + signal.current = NULL; + CHECK_EMIT(2) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l2); + + signal.current = &signal.l1; + CHECK_EMIT(1) + /* l2 was added before l1, so l2 is fired first, which by readding l1 + * removes it from the current list that is being fired, so 1 is correct */ + CHECK_EMIT(1) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + + signal.l1.notify = notify_empty; + signal.current = &signal.l2; + CHECK_EMIT(2) + CHECK_EMIT(2) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + + signal.l1.notify = notify_empty; + signal.current = &signal.l1; + CHECK_EMIT(2) + /* same as before, by readding l1 in the first emit, it now is fired + * after l2, so on the second emit it is not fired at all. */ + CHECK_EMIT(1) +} + +static void notify_addandget(struct wl_listener *l, void *data) +{ + struct signal *signal = data; + wl_list_remove(&signal->current->link); + wl_list_init(&signal->current->link); + wl_priv_signal_add(&signal->signal, signal->current); + + assert(wl_priv_signal_get(&signal->signal, signal->current->notify) != NULL); + + signal->count++; +} + +static void notify_get(struct wl_listener *l, void *data) +{ + struct signal *signal = data; + assert(wl_priv_signal_get(&signal->signal, signal->current->notify) == signal->current); + signal->count++; +} + +TEST(signal_get_listener) +{ + test_set_timeout(4); + + struct signal signal; + + signal.l1.notify = notify_addandget; + signal.l2.notify = notify_get; + + INIT + wl_priv_signal_add(&signal.signal, &signal.l1); + + signal.current = &signal.l2; + CHECK_EMIT(1) + + INIT + wl_priv_signal_add(&signal.signal, &signal.l2); + + signal.current = &signal.l2; + CHECK_EMIT(1) + + INIT + signal.l1.notify = notify_get; + signal.l2.notify = notify_empty; + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + + CHECK_EMIT(2) + + INIT + signal.l1.notify = notify_empty; + signal.l2.notify = notify_get; + wl_priv_signal_add(&signal.signal, &signal.l1); + wl_priv_signal_add(&signal.signal, &signal.l2); + + signal.current = &signal.l1; + CHECK_EMIT(2) +} From 7454aa9bb9569a1d63f6bcb1938e165ea370a4a5 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Tue, 24 Jan 2017 16:34:29 +0200 Subject: [PATCH 0418/1152] server: use the new wl_priv_signal in wl_client Signed-off-by: Giulio Camuffo Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 1482d5e7..06f8ba28 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -78,10 +78,10 @@ struct wl_client { uint32_t mask; struct wl_list link; struct wl_map objects; - struct wl_signal destroy_signal; + struct wl_priv_signal destroy_signal; struct ucred ucred; int error; - struct wl_signal resource_created_signal; + struct wl_priv_signal resource_created_signal; }; struct wl_display { @@ -460,7 +460,7 @@ wl_client_create(struct wl_display *display, int fd) if (client == NULL) return NULL; - wl_signal_init(&client->resource_created_signal); + wl_priv_signal_init(&client->resource_created_signal); client->display = display; client->source = wl_event_loop_add_fd(display->loop, fd, WL_EVENT_READABLE, @@ -483,7 +483,7 @@ wl_client_create(struct wl_display *display, int fd) if (wl_map_insert_at(&client->objects, 0, 0, NULL) < 0) goto err_map; - wl_signal_init(&client->destroy_signal); + wl_priv_signal_init(&client->destroy_signal); if (bind_display(client, display) < 0) goto err_map; @@ -745,14 +745,14 @@ WL_EXPORT void wl_client_add_destroy_listener(struct wl_client *client, struct wl_listener *listener) { - wl_signal_add(&client->destroy_signal, listener); + wl_priv_signal_add(&client->destroy_signal, listener); } WL_EXPORT struct wl_listener * wl_client_get_destroy_listener(struct wl_client *client, wl_notify_func_t notify) { - return wl_signal_get(&client->destroy_signal, notify); + return wl_priv_signal_get(&client->destroy_signal, notify); } WL_EXPORT void @@ -760,7 +760,7 @@ wl_client_destroy(struct wl_client *client) { uint32_t serial = 0; - wl_signal_emit(&client->destroy_signal, client); + wl_priv_signal_emit(&client->destroy_signal, client); wl_client_flush(client); wl_map_for_each(&client->objects, destroy_resource, &serial); @@ -1575,7 +1575,7 @@ wl_resource_create(struct wl_client *client, return NULL; } - wl_signal_emit(&client->resource_created_signal, resource); + wl_priv_signal_emit(&client->resource_created_signal, resource); return resource; } @@ -1763,7 +1763,7 @@ WL_EXPORT void wl_client_add_resource_created_listener(struct wl_client *client, struct wl_listener *listener) { - wl_signal_add(&client->resource_created_signal, listener); + wl_priv_signal_add(&client->resource_created_signal, listener); } struct wl_resource_iterator_context { From c44eed1c064999f1e0297088bacd56c602dee2eb Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Tue, 24 Jan 2017 16:34:30 +0200 Subject: [PATCH 0419/1152] server: use the new wl_priv_signal for wl_resource The old wl_signal is kept for backwards compatibility, as that is also present in the deprecated public wl_resource struct, and that must be kept working. Signed-off-by: Giulio Camuffo Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 52 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 06f8ba28..ac634da5 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -120,11 +120,16 @@ struct wl_resource { struct wl_object object; wl_resource_destroy_func_t destroy; struct wl_list link; - struct wl_signal destroy_signal; + /* Unfortunately some users of libwayland (e.g. mesa) still use the + * deprecated wl_resource struct, even if creating it with the new + * wl_resource_create(). So we cannot change the layout of the struct + * unless after the data field. */ + struct wl_signal deprecated_destroy_signal; struct wl_client *client; void *data; int version; wl_dispatcher_func_t dispatcher; + struct wl_priv_signal destroy_signal; }; struct wl_protocol_logger { @@ -600,6 +605,31 @@ wl_resource_post_no_memory(struct wl_resource *resource) WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); } +/** Detect if a wl_resource uses the deprecated public definition. + * + * Before Wayland 1.2.0, the definition of struct wl_resource was public. + * It was made opaque just before 1.2.0, and later new fields were added. + * The new fields cannot be accessed if a program is using the deprecated + * defition, as there would not be memory allocated for them. + * + * The creation pattern for the deprecated definition was wl_resource_init() + * followed by wl_client_add_resource(). wl_resource_init() was an inline + * function and no longer exists, but binaries might still carry it. + * wl_client_add_resource() still exists for ABI compatiblity. + */ +static bool +resource_is_deprecated(struct wl_resource *resource) +{ + struct wl_map *map = &resource->client->objects; + int id = resource->object.id; + + /* wl_client_add_resource() marks deprecated resources with the flag. */ + if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY) + return true; + + return false; +} + static enum wl_iterator_result destroy_resource(void *element, void *data) { @@ -607,7 +637,11 @@ destroy_resource(void *element, void *data) struct wl_client *client = resource->client; uint32_t flags; - wl_signal_emit(&resource->destroy_signal, resource); + wl_signal_emit(&resource->deprecated_destroy_signal, resource); + /* Don't emit the new signal for deprecated resources, as that would + * access memory outside the bounds of the deprecated struct */ + if (!resource_is_deprecated(resource)) + wl_priv_signal_emit(&resource->destroy_signal, resource); flags = wl_map_lookup_flags(&client->objects, resource->object.id); if (resource->destroy) @@ -719,14 +753,19 @@ WL_EXPORT void wl_resource_add_destroy_listener(struct wl_resource *resource, struct wl_listener * listener) { - wl_signal_add(&resource->destroy_signal, listener); + if (resource_is_deprecated(resource)) + wl_signal_add(&resource->deprecated_destroy_signal, listener); + else + wl_priv_signal_add(&resource->destroy_signal, listener); } WL_EXPORT struct wl_listener * wl_resource_get_destroy_listener(struct wl_resource *resource, wl_notify_func_t notify) { - return wl_signal_get(&resource->destroy_signal, notify); + if (resource_is_deprecated(resource)) + return wl_signal_get(&resource->deprecated_destroy_signal, notify); + return wl_priv_signal_get(&resource->destroy_signal, notify); } /** Retrieve the interface name (class) of a resource object. @@ -1559,7 +1598,8 @@ wl_resource_create(struct wl_client *client, resource->object.interface = interface; resource->object.implementation = NULL; - wl_signal_init(&resource->destroy_signal); + wl_signal_init(&resource->deprecated_destroy_signal); + wl_priv_signal_init(&resource->destroy_signal); resource->destroy = NULL; resource->client = client; @@ -1927,7 +1967,7 @@ wl_client_add_resource(struct wl_client *client, } resource->client = client; - wl_signal_init(&resource->destroy_signal); + wl_signal_init(&resource->deprecated_destroy_signal); return resource->object.id; } From 5fbc9daa409371d15ffb9012cc21dddc934fad4a Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 24 Jan 2017 12:07:19 -0600 Subject: [PATCH 0420/1152] server: Refactor array send functions These have grown a little in size but are almost identical, factor out the common code. Signed-off-by: Derek Foreman Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index ac634da5..a981fdae 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -168,9 +168,10 @@ log_closure(struct wl_resource *resource, } } -WL_EXPORT void -wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, - union wl_argument *args) +static void +handle_array(struct wl_resource *resource, uint32_t opcode, + union wl_argument *args, + int (*send_func)(struct wl_closure *, struct wl_connection *)) { struct wl_closure *closure; struct wl_object *object = &resource->object; @@ -183,7 +184,7 @@ wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, return; } - if (wl_closure_send(closure, resource->client->connection)) + if (send_func(closure, resource->client->connection)) resource->client->error = 1; log_closure(resource, closure, true); @@ -191,6 +192,13 @@ wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, wl_closure_destroy(closure); } +WL_EXPORT void +wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, + union wl_argument *args) +{ + handle_array(resource, opcode, args, wl_closure_send); +} + WL_EXPORT void wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...) { @@ -211,23 +219,7 @@ WL_EXPORT void wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args) { - struct wl_closure *closure; - struct wl_object *object = &resource->object; - - closure = wl_closure_marshal(object, opcode, args, - &object->interface->events[opcode]); - - if (closure == NULL) { - resource->client->error = 1; - return; - } - - if (wl_closure_queue(closure, resource->client->connection)) - resource->client->error = 1; - - log_closure(resource, closure, true); - - wl_closure_destroy(closure); + handle_array(resource, opcode, args, wl_closure_queue); } WL_EXPORT void From efae9532e82e1faeb737fe0d3cf5932026ce1e6f Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 24 Jan 2017 12:07:20 -0600 Subject: [PATCH 0421/1152] server: Disallow sending events to clients after posting an error Until now, we haven't done anything to prevent sending additional events to clients after posting an error. Acked-by: Daniel Stone Signed-off-by: Derek Foreman Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index a981fdae..0a5eacbd 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -176,6 +176,9 @@ handle_array(struct wl_resource *resource, uint32_t opcode, struct wl_closure *closure; struct wl_object *object = &resource->object; + if (resource->client->error) + return; + closure = wl_closure_marshal(object, opcode, args, &object->interface->events[opcode]); @@ -249,8 +252,6 @@ wl_resource_post_error(struct wl_resource *resource, vsnprintf(buffer, sizeof buffer, msg, ap); va_end(ap); - client->error = 1; - /* * When a client aborts, its resources are destroyed in id order, * which means the display resource is destroyed first. If destruction @@ -258,11 +259,12 @@ wl_resource_post_error(struct wl_resource *resource, * with a NULL display_resource. Do not try to send errors to an * already dead client. */ - if (!client->display_resource) + if (client->error || !client->display_resource) return; wl_resource_post_event(client->display_resource, WL_DISPLAY_ERROR, resource, code, buffer); + client->error = 1; } static int From de908658945ef8e13b27b32a7a69f14b3f9356df Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 24 Jan 2017 12:07:21 -0600 Subject: [PATCH 0422/1152] wayland-server: log an error for events with wrong client objects Check that all the objects in an event belong to the same client as the resource posting it. This prevents a compositor from accidentally mixing client objects and posting an event that causes a client to abort with a cryptic message. Instead the client will now be disconnected as it is when the compositor tries to send a null for a non-nullable object, and a log message will be printed by the compositor. Reviewed-by: Yong Bakos Reviewed-by: Bryce Harrington Signed-off-by: Derek Foreman Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 0a5eacbd..cdd46fa5 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -168,6 +168,36 @@ log_closure(struct wl_resource *resource, } } +static bool +verify_objects(struct wl_resource *resource, uint32_t opcode, + union wl_argument *args) +{ + struct wl_object *object = &resource->object; + const char *signature = object->interface->events[opcode].signature; + struct argument_details arg; + struct wl_resource *res; + int count, i; + + count = arg_count_for_signature(signature); + for (i = 0; i < count; i++) { + signature = get_next_argument(signature, &arg); + switch (arg.type) { + case 'n': + case 'o': + res = (struct wl_resource *) (args[i].o); + if (res && res->client != resource->client) { + wl_log("compositor bug: The compositor " + "tried to use an object from one " + "client in a '%s.%s' for a different " + "client.\n", object->interface->name, + object->interface->events[opcode].name); + return false; + } + } + } + return true; +} + static void handle_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args, @@ -179,6 +209,11 @@ handle_array(struct wl_resource *resource, uint32_t opcode, if (resource->client->error) return; + if (!verify_objects(resource, opcode, args)) { + resource->client->error = 1; + return; + } + closure = wl_closure_marshal(object, opcode, args, &object->interface->events[opcode]); From e89d0a66843eb3cb4d888c594ad87ef731e51697 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Mon, 23 Jan 2017 06:16:30 -0800 Subject: [PATCH 0423/1152] dtddata: Use standard permission notice Signed-off-by: Yong Bakos Reviewed-by: Daniel Stone --- src/dtddata.S | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/dtddata.S b/src/dtddata.S index ce51133c..24050665 100644 --- a/src/dtddata.S +++ b/src/dtddata.S @@ -1,23 +1,26 @@ /* * Copyright 2015 Collabora, Ltd. * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the copyright holders not be used in - * advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. The copyright holders make - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ /* From 8fe8a2bb1e2b893bd39899f7481d5cf5fa303b29 Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Wed, 23 Nov 2016 07:38:01 -0800 Subject: [PATCH 0424/1152] tests: Test wl_argument_from_va_list connection-test.c did not cover wl_argument_from_va_list, so add one test that specifically tests this method. Signed-off-by: Yong Bakos Reviewed-by: Daniel Stone --- tests/connection-test.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/connection-test.c b/tests/connection-test.c index 3e34f779..1c688f12 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -130,6 +130,41 @@ TEST(connection_queue) close(s[1]); } +static void +va_list_wrapper(const char *signature, union wl_argument *args, int count, ...) +{ + va_list ap; + va_start(ap, count); + wl_argument_from_va_list(signature, args, count, ap); + va_end(ap); +} + +TEST(argument_from_va_list) +{ + union wl_argument args[WL_CLOSURE_MAX_ARGS]; + struct wl_object fake_object; + struct wl_array fake_array; + + va_list_wrapper("i", args, 1, 100); + assert(args[0].i == 100); + + va_list_wrapper("is", args, 2, 101, "value"); + assert(args[0].i == 101); + assert(strcmp(args[1].s, "value") == 0); + + va_list_wrapper("?iuf?sonah", args, 8, + 102, 103, wl_fixed_from_int(104), "value", + &fake_object, 105, &fake_array, 106); + assert(args[0].i == 102); + assert(args[1].u == 103); + assert(args[2].f == wl_fixed_from_int(104)); + assert(strcmp(args[3].s, "value") == 0); + assert(args[4].o == &fake_object); + assert(args[5].n == 105); + assert(args[6].a == &fake_array); + assert(args[7].h == 106); +} + struct marshal_data { struct wl_connection *read_connection; struct wl_connection *write_connection; From 56f2dad6d2ac04e179d43d525f6213031dcb4d62 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 25 Jan 2017 14:24:44 +0200 Subject: [PATCH 0425/1152] wayland-server: hide wl_priv_signal from doxygen Fix this set of warnings appearing three times during a build: /home/pq/git/wayland/src/wayland-server.c:1868: warning: class `wl_priv_signal' for related function `wl_priv_signal_init' is not documented. /home/pq/git/wayland/src/wayland-server.c:1884: warning: class `wl_priv_signal' for related function `wl_priv_signal_add' is not documented. /home/pq/git/wayland/src/wayland-server.c:1899: warning: class `wl_priv_signal' for related function `wl_priv_signal_get' is not documented. Our Wayland docbook don't include private things, so make sure these do not end up there. This removes the mention of wl_priv_signal_emit from the Server API docbook. I have no idea why the other functions did not appear there. Signed-off-by: Pekka Paalanen Reviewed-by: Yong Bakos --- src/wayland-server.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index cdd46fa5..6a8b3e4b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1881,6 +1881,8 @@ wl_client_for_each_resource(struct wl_client *client, wl_map_for_each(&client->objects, resource_iterator_helper, &context); } +/** \cond INTERNAL */ + /** Initialize a wl_priv_signal object * * wl_priv_signal is a safer implementation of a signal type, with the same API @@ -1972,6 +1974,8 @@ wl_priv_signal_emit(struct wl_priv_signal *signal, void *data) } } +/** \endcond INTERNAL */ + /** \cond */ /* Deprecated functions below. */ uint32_t From 6161d7dd0efd33339a90bdfbc6f2575ff16f1b2f Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 7 Feb 2017 15:14:56 -0800 Subject: [PATCH 0426/1152] configure.ac: bump to version 1.12.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7520b242..2a3d5e3b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [12]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 24df0fb6b3835c3b4574847491eecae769af4c2c Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 14 Feb 2017 12:56:55 -0800 Subject: [PATCH 0427/1152] configure.ac: bump to version 1.12.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2a3d5e3b..c50027ba 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [12]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 1361da9cd5a719b32d978485a29920429a31ed25 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 21 Feb 2017 13:27:16 -0800 Subject: [PATCH 0428/1152] configure.ac: bump to version 1.13.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c50027ba..fcce4ce9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [12]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [13]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From f8c93078f8ec4f754dfd7dc5de1c9833a3b0f453 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 21 Feb 2017 14:25:03 -0800 Subject: [PATCH 0429/1152] configure.ac: bump version to 1.13.90 for open development Signed-off-by: Bryce Harrington --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fcce4ce9..b583bef3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [13]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 680a6b32de49896dc290968f83a1e4cce315888e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 23 Feb 2017 13:47:41 +0100 Subject: [PATCH 0430/1152] tests: Fix "new ID" type handling in argument_from_va_list test New IDs are internally dealt with as objects, however this test expected to deal with 'n' as the uint32_t type that's just seen through the wire. We should give it an object instead, and expect an object from it. https://bugs.freedesktop.org/show_bug.cgi?id=99899 Signed-off-by: Carlos Garnacho Reviewed-by: Pekka Paalanen Tested-by: Kalev Lember Reviewed-by: Yong Bakos --- tests/connection-test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/connection-test.c b/tests/connection-test.c index 1c688f12..8be6c38d 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -142,7 +142,7 @@ va_list_wrapper(const char *signature, union wl_argument *args, int count, ...) TEST(argument_from_va_list) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; - struct wl_object fake_object; + struct wl_object fake_object, fake_new_object; struct wl_array fake_array; va_list_wrapper("i", args, 1, 100); @@ -154,13 +154,13 @@ TEST(argument_from_va_list) va_list_wrapper("?iuf?sonah", args, 8, 102, 103, wl_fixed_from_int(104), "value", - &fake_object, 105, &fake_array, 106); + &fake_object, &fake_new_object, &fake_array, 106); assert(args[0].i == 102); assert(args[1].u == 103); assert(args[2].f == wl_fixed_from_int(104)); assert(strcmp(args[3].s, "value") == 0); assert(args[4].o == &fake_object); - assert(args[5].n == 105); + assert(args[5].o == &fake_new_object); assert(args[6].a == &fake_array); assert(args[7].h == 106); } From 9b78be6bb0df43b7fe197946fe764e8a758006a8 Mon Sep 17 00:00:00 2001 From: Sergi Granell Date: Sun, 26 Feb 2017 22:55:53 +0100 Subject: [PATCH 0431/1152] wayland-server: Remove unused members from struct wl_client Those struct members are no longer used so we can remove them. Signed-off-by: Sergi Granell Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 6a8b3e4b..82a3b01f 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -74,8 +74,6 @@ struct wl_client { struct wl_event_source *source; struct wl_display *display; struct wl_resource *display_resource; - uint32_t id_count; - uint32_t mask; struct wl_list link; struct wl_map objects; struct wl_priv_signal destroy_signal; From 654dee85c65e554b3f0d82350d6740520e4e7d56 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 21 Feb 2017 16:14:26 +0000 Subject: [PATCH 0432/1152] wayland-util: do not export the wl_map_* API Used only internally and explicitly marked as such with commit cf04b0a18f2 ("Move private definitions and prototypes to new zwayland-private.h") Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- src/wayland-util.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 077fec75..cab7fc50 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -177,21 +177,21 @@ union map_entry { #define map_entry_get_data(entry) ((void *)((entry).next & ~(uintptr_t)0x3)) #define map_entry_get_flags(entry) (((entry).next >> 1) & 0x1) -WL_EXPORT void +void wl_map_init(struct wl_map *map, uint32_t side) { memset(map, 0, sizeof *map); map->side = side; } -WL_EXPORT void +void wl_map_release(struct wl_map *map) { wl_array_release(&map->client_entries); wl_array_release(&map->server_entries); } -WL_EXPORT uint32_t +uint32_t wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) { union map_entry *start, *entry; @@ -223,7 +223,7 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) return (entry - start) + base; } -WL_EXPORT int +int wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) { union map_entry *start; @@ -251,7 +251,7 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) return 0; } -WL_EXPORT int +int wl_map_reserve_new(struct wl_map *map, uint32_t i) { union map_entry *start; @@ -290,7 +290,7 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) return 0; } -WL_EXPORT void +void wl_map_remove(struct wl_map *map, uint32_t i) { union map_entry *start; @@ -314,7 +314,7 @@ wl_map_remove(struct wl_map *map, uint32_t i) map->free_list = (i << 1) | 1; } -WL_EXPORT void * +void * wl_map_lookup(struct wl_map *map, uint32_t i) { union map_entry *start; @@ -337,7 +337,7 @@ wl_map_lookup(struct wl_map *map, uint32_t i) return NULL; } -WL_EXPORT uint32_t +uint32_t wl_map_lookup_flags(struct wl_map *map, uint32_t i) { union map_entry *start; @@ -379,7 +379,7 @@ for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) return ret; } -WL_EXPORT void +void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) { enum wl_iterator_result ret; From 9452cc53da5bef65a38e4d5a66a838c61e49f6cd Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Thu, 16 Mar 2017 11:46:06 +0000 Subject: [PATCH 0433/1152] connection-test: fix assert Signed-off-by: Eric Engestrom Reviewed-by: Pekka Paalanen --- tests/connection-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/connection-test.c b/tests/connection-test.c index 8be6c38d..157e1bc9 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -603,8 +603,8 @@ suu_handler(void *data, struct wl_object *object, int *done = data; assert(strcmp(s, "foo") == 0); - assert(u1 = 500); - assert(u2 = 404040); + assert(u1 == 500); + assert(u2 == 404040); *done = 1; } From 3f2c19469734a712ced0a1b17559d7e3bd744d50 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Fri, 17 Mar 2017 17:35:38 +0000 Subject: [PATCH 0434/1152] scanner: Reword fallthrough comment to quiet GCC GCC 7 now requires an explicit comment noting that case statements without a break fall through. We already had one of those in the scanner, but GCC wasn't smart enough to pick it up. Quiet the warning by making the comment less elaborate. Signed-off-by: Daniel Stone Reviewed-by: Yong Bakos --- src/scanner.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index a6c334fb..517068c4 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -740,9 +740,7 @@ start_element(void *data, const char *element_name, const char **atts) switch (arg->type) { case NEW_ID: ctx->message->new_id_count++; - - /* Fall through to OBJECT case. */ - + /* fallthrough */ case OBJECT: if (interface_name) arg->interface_name = xstrdup(interface_name); From 0eefe99fe0683ae409b665a8b18cc7eb648c6c0c Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 6 Apr 2017 15:09:37 +0100 Subject: [PATCH 0435/1152] docs: Reference Contributor Covenant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All fd.o projects are now covered by the Contributor Covenant. Include a reference to this in the Contributing doc, making it clear that we are all expected to behave like human beings. Signed-off-by: Daniel Stone Reviewed-by: Yong Bakos Acked-by: Pekka Paalanen Acked-by: Jonas Ådahl --- doc/Contributing | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/Contributing b/doc/Contributing index c790a071..9475271a 100644 --- a/doc/Contributing +++ b/doc/Contributing @@ -159,6 +159,19 @@ my_function(void) x = function_with_a_really_long_name(parameter1, parameter2, parameter3, parameter4); + +== Conduct == + +As a freedesktop.org project, Wayland follows the Contributor Covenant, +found at: +https://www.freedesktop.org/wiki/CodeOfConduct + +Please conduct yourself in a respectful and civilised manner when +interacting with community members on mailing lists, IRC, or bug +trackers. The community represents the project as a whole, and abusive +or bullying behaviour is not tolerated by the project. + + == Licensing == Wayland is licensed with the intention to be usable anywhere X.org is. From f52c50baad90f9c44d1a7ae21802204b4f9702d9 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 11 Jul 2017 19:07:55 -0700 Subject: [PATCH 0436/1152] configure.ac: bump to version 1.13.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b583bef3..7ea23eab 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [13]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 897256d4190caf276363b8ce11de8846094ea553 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 25 Jul 2017 16:25:01 -0700 Subject: [PATCH 0437/1152] configure.ac: bump to version 1.13.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7ea23eab..d638b07a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [13]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 042e7eadd8e852ef466592f0f0be0dab84736187 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Thu, 1 Jun 2017 22:48:29 -0400 Subject: [PATCH 0438/1152] Switch graphviz files to use HTML-style labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With recent versions of graphviz, generation of the diagrams in the documentation fails with: /usr/bin/dot -Tpng -oxml/x-architecture.png dot/x-architecture.gv Warning: flat edge between adjacent nodes one of which has a record shape - replace records with HTML-like labels Edge xserver -> comp Error: getsplinepoints: no spline points available for edge (xserver,comp) Error: lost xserver comp edge Error: lost xserver comp edge Error: lost comp xserver edge Error: lost comp xserver edge http://www.graphviz.org/content/i-havent-been-able-render-these-files-graphviz-226 indicates that the error message basically means that the authors of graphviz consider record-style labels to be deprecated and are no longer fixing errors with them. This patch changes the labels to be in the HTML style, which seems to require duplicating style between all the nodes, but it's not like these files are often edited. The result is not exactly the same but is quite similar. Reviewed-by: Armin Krezović Tested-by: Armin Krezović --- doc/doxygen/dot/wayland-architecture.gv | 13 +++++-------- doc/doxygen/dot/x-architecture.gv | 17 ++++++++--------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/doc/doxygen/dot/wayland-architecture.gv b/doc/doxygen/dot/wayland-architecture.gv index 2d5db841..f2c35075 100644 --- a/doc/doxygen/dot/wayland-architecture.gv +++ b/doc/doxygen/dot/wayland-architecture.gv @@ -9,21 +9,18 @@ digraph arch_wayland { ] node[ - shape="Mrecord", color=none, - fillcolor="#ffbc00", - style="filled", + margin=0, fontname="DejaVu Sans", fontsize="18", ] - c1 [label="Wayland Client", URL="#c1"] - c2 [label="Wayland Client", URL="#c2"] + c1 [label=<
Wayland Client
>, URL="#c1"] + c2 [label=<
Wayland Client
>, URL="#c2"] - comp [tooltip="Wayland Compositor", label="|{|Wayland\nCompositor|}|", URL="#comp"] - - impl [tooltip="KMS evdev Kernel", label="|{{KMS|evdev}|Kernel}|", URL="#impl"] + comp [tooltip="Wayland Compositor", label=<

Wayland
Compositor

>, URL="#comp"] + impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] c1 -> comp [taillabel="③", labeldistance=2.5, URL="#step_3"]; c2 -> comp; diff --git a/doc/doxygen/dot/x-architecture.gv b/doc/doxygen/dot/x-architecture.gv index 4ea49bfa..b223d1dc 100644 --- a/doc/doxygen/dot/x-architecture.gv +++ b/doc/doxygen/dot/x-architecture.gv @@ -9,28 +9,27 @@ digraph arch_x { ] node[ - shape="Mrecord", + shape="none", color=none, - fillcolor="#ffbc00", - style="filled", + margin=0, fontname="DejaVu Sans", fontsize="18", ] { rank=same; - c1 [label="X Client", URL="#c1"] - c3 [label="X Client", URL="#c3"] + c1 [label=<
X Client
>, URL="#c1"] + c3 [label=<
X Client
>, URL="#c3"] } - c2 [label="X Client", URL="#c2"] + c2 [label=<
X Client
>, URL="#c2"] { rank=same; - xserver [tooltip="X Server", label="|{|X Server|}|", URL="#xserver"] - comp [tooltip="Compositor", label="|{|Compositor|}|", URL="#comp"] + xserver [tooltip="X Server", label=<

X Server

>, URL="#xserver"] + comp [tooltip="Compositor", label=<

Compositor

>, URL="#comp"] } - impl [tooltip="KMS evdev Kernel", label="|{{KMS|evdev}|Kernel}|", URL="#impl"] + impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] c1 -> xserver [taillabel="③", labeldistance=2, URL="#step_3"]; c2 -> xserver; From 269c1434b4f5442a5625b662dd4bef10d2d22910 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 1 Aug 2017 11:12:43 -0700 Subject: [PATCH 0439/1152] configure.ac: bump to version 1.13.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d638b07a..6739742e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [13]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 989cf03d1ce05d2b2481758e746f7299a1086880 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 8 Aug 2017 11:20:35 -0700 Subject: [PATCH 0440/1152] configure.ac: bump to version 1.14.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6739742e..8ac54e8f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [13]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [14]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 0b991b62b864a123db971a56adfc14f5e2255cac Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Tue, 8 Aug 2017 12:03:27 -0700 Subject: [PATCH 0441/1152] Reopen master for regular development A 1.14 branch has been established for stable release work. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8ac54e8f..fcb9718b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [14]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 12509e46b73e4c01c5d21a3c3b39e835d206d64d Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Wed, 26 Jul 2017 14:56:17 +0100 Subject: [PATCH 0442/1152] scanner: remove unused scanner.mk Nothing in the existing codebase references the file. Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- src/scanner.mk | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/scanner.mk diff --git a/src/scanner.mk b/src/scanner.mk deleted file mode 100644 index 1b6963ce..00000000 --- a/src/scanner.mk +++ /dev/null @@ -1,8 +0,0 @@ -%-protocol.c : $(protocoldir)/%.xml - $(AM_V_GEN)$(wayland_scanner) code < $< > $@ - -%-server-protocol.h : $(protocoldir)/%.xml - $(AM_V_GEN)$(wayland_scanner) server-header < $< > $@ - -%-client-protocol.h : $(protocoldir)/%.xml - $(AM_V_GEN)$(wayland_scanner) client-header < $< > $@ From 22be3c7b90ef6156f7793d36d341777222d5e36c Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Wed, 26 Jul 2017 14:56:18 +0100 Subject: [PATCH 0443/1152] scanner: use tabs for indentation. File uses tabs, barring the few instances fixed with this patch. Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- src/scanner.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 517068c4..c345ed6b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -70,9 +70,9 @@ usage(int ret) fprintf(stderr, " -h, --help display this help and exit.\n" " -v, --version print the wayland library version that\n" " the scanner was built against.\n" - " -c, --include-core-only include the core version of the headers,\n" - " that is e.g. wayland-client-core.h instead\n" - " of wayland-client.h.\n"); + " -c, --include-core-only include the core version of the headers,\n" + " that is e.g. wayland-client-core.h instead\n" + " of wayland-client.h.\n"); exit(ret); } From b88ada076094ba160ff58229de1259e0e2a26c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 3 Jul 2017 17:16:44 +0800 Subject: [PATCH 0444/1152] Pass input/output files as arguments to wayland-scanner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When input/output files are passed as arguments to wayland-scanner, instead of using stdin/stdout, warning and error messages will contain the file name, together with line number, of the warning/error. Doing this helps IDEs jump to the correct line. Signed-off-by: Jonas Ådahl Reviewed-by: Emil Velikov [Pekka: dropped the src/scanner.mk hunk, file deleted] Signed-off-by: Pekka Paalanen --- Makefile.am | 6 +++--- wayland-scanner.mk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index d0c8bd3e..fdc56899 100644 --- a/Makefile.am +++ b/Makefile.am @@ -97,13 +97,13 @@ nodist_libwayland_client_la_SOURCES = \ pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code $< $@ protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header $< $@ protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header $< $@ protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header -c < $< > $@ diff --git a/wayland-scanner.mk b/wayland-scanner.mk index 0a72062b..c174e6bd 100644 --- a/wayland-scanner.mk +++ b/wayland-scanner.mk @@ -1,8 +1,8 @@ %-protocol.c : $(wayland_protocoldir)/%.xml - $(AM_V_GEN)$(wayland_scanner) code < $< > $@ + $(AM_V_GEN)$(wayland_scanner) code $< $@ %-server-protocol.h : $(wayland_protocoldir)/%.xml - $(AM_V_GEN)$(wayland_scanner) server-header < $< > $@ + $(AM_V_GEN)$(wayland_scanner) server-header $< $@ %-client-protocol.h : $(wayland_protocoldir)/%.xml - $(AM_V_GEN)$(wayland_scanner) client-header < $< > $@ + $(AM_V_GEN)$(wayland_scanner) client-header $< $@ From 3ea73cba0446886632cd24442203fda47cb3c220 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 3 Mar 2017 17:50:22 +0200 Subject: [PATCH 0445/1152] server: document wl_event_loop and wl_event_source This documents all the public API related to wl_event_loop and wl_event_source objects. Signed-off-by: Pekka Paalanen Reviewed-by: Yong Bakos [Pekka: fixed typos pointed by Yong] [Pekka: fixed typos pointed by Christopher] Reviewed-By: Christopher James Halse Rogers --- doc/doxygen/Makefile.am | 1 + src/event-loop.c | 244 +++++++++++++++++++++++++++++++++++++- src/wayland-server-core.h | 77 ++++++++++++ 3 files changed, 321 insertions(+), 1 deletion(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 276a395b..f8b0b3aa 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -19,6 +19,7 @@ scanned_src_files_Client = \ scanned_src_files_Server = \ $(scanned_src_files_shared) \ + $(top_srcdir)/src/event-loop.c \ $(top_srcdir)/src/wayland-server.c \ $(top_srcdir)/src/wayland-server.h \ $(top_srcdir)/src/wayland-server-core.h \ diff --git a/src/event-loop.c b/src/event-loop.c index 6130d2af..49e48bf4 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -42,6 +42,8 @@ #include "wayland-server-core.h" #include "wayland-os.h" +/** \cond INTERNAL */ + struct wl_event_loop { int epoll_fd; struct wl_list check_list; @@ -70,6 +72,8 @@ struct wl_event_source_fd { int fd; }; +/** \endcond */ + static int wl_event_source_fd_dispatch(struct wl_event_source *source, struct epoll_event *ep) @@ -125,6 +129,30 @@ add_source(struct wl_event_loop *loop, return source; } +/** Create a file descriptor event source + * + * \param loop The event loop that will process the new source. + * \param fd The file descriptor to watch. + * \param mask A bitwise-or of which events to watch for: \c WL_EVENT_READABLE, + * \c WL_EVENT_WRITABLE. + * \param func The file descriptor dispatch function. + * \param data User data. + * \return A new file descriptor event source. + * + * The given file descriptor is initially watched for the events given in + * \c mask. This can be changed as needed with wl_event_source_fd_update(). + * + * If it is possible that program execution causes the file descriptor to be + * read while leaving the data in a buffer without actually processing it, + * it may be necessary to register the file descriptor source to be re-checked, + * see wl_event_source_check(). This will ensure that the dispatch function + * gets called even if the file descriptor is not readable or writable + * anymore. This is especially useful with IPC libraries that automatically + * buffer incoming data, possibly as a side-effect of other operations. + * + * \sa wl_event_loop_fd_func_t + * \memberof wl_event_source + */ WL_EXPORT struct wl_event_source * wl_event_loop_add_fd(struct wl_event_loop *loop, int fd, uint32_t mask, @@ -145,6 +173,26 @@ wl_event_loop_add_fd(struct wl_event_loop *loop, return add_source(loop, &source->base, mask, data); } +/** Update a file descriptor source's event mask + * + * \param source The file descriptor event source to update. + * \param mask The new mask, a bitwise-or of: \c WL_EVENT_READABLE, + * \c WL_EVENT_WRITABLE. + * \return 0 on success, -1 on failure. + * + * This changes which events, readable and/or writable, cause the dispatch + * callback to be called on. + * + * File descriptors are usually writable to begin with, so they do not need to + * be polled for writable until a write actually fails. When a write fails, + * the event mask can be changed to poll for readable and writable, delivering + * a dispatch callback when it is possible to write more. Once all data has + * been written, the mask can be changed to poll only for readable to avoid + * busy-looping on dispatch. + * + * \sa wl_event_loop_add_fd() + * \memberof wl_event_source + */ WL_EXPORT int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask) { @@ -161,11 +209,15 @@ wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask) return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep); } +/** \cond INTERNAL */ + struct wl_event_source_timer { struct wl_event_source base; wl_event_loop_timer_func_t func; }; +/** \endcond */ + static int wl_event_source_timer_dispatch(struct wl_event_source *source, struct epoll_event *ep) @@ -187,6 +239,19 @@ struct wl_event_source_interface timer_source_interface = { wl_event_source_timer_dispatch, }; +/** Create a timer event source + * + * \param loop The event loop that will process the new source. + * \param func The timer dispatch function. + * \param data User data. + * \return A new timer event source. + * + * The timer is initially disarmed. It needs to be armed with a call to + * wl_event_source_timer_update() before it can trigger a dispatch call. + * + * \sa wl_event_loop_timer_func_t + * \memberof wl_event_source + */ WL_EXPORT struct wl_event_source * wl_event_loop_add_timer(struct wl_event_loop *loop, wl_event_loop_timer_func_t func, @@ -206,6 +271,22 @@ wl_event_loop_add_timer(struct wl_event_loop *loop, return add_source(loop, &source->base, WL_EVENT_READABLE, data); } +/** Arm or disarm a timer + * + * \param source The timer event source to modify. + * \param ms_delay The timeout in milliseconds. + * \return 0 on success, -1 on failure. + * + * If the timeout is zero, the timer is disarmed. + * + * If the timeout is non-zero, the timer is set to expire after the given + * timeout in milliseconds. When the timer expires, the dispatch function + * set with wl_event_loop_add_timer() is called once from + * wl_event_loop_dispatch(). If another dispatch is desired after another + * expiry, wl_event_source_timer_update() needs to be called again. + * + * \memberof wl_event_source + */ WL_EXPORT int wl_event_source_timer_update(struct wl_event_source *source, int ms_delay) { @@ -221,12 +302,16 @@ wl_event_source_timer_update(struct wl_event_source *source, int ms_delay) return 0; } +/** \cond INTERNAL */ + struct wl_event_source_signal { struct wl_event_source base; int signal_number; wl_event_loop_signal_func_t func; }; +/** \endcond */ + static int wl_event_source_signal_dispatch(struct wl_event_source *source, struct epoll_event *ep) @@ -249,6 +334,25 @@ struct wl_event_source_interface signal_source_interface = { wl_event_source_signal_dispatch, }; +/** Create a POSIX signal event source + * + * \param loop The event loop that will process the new source. + * \param signal_number Number of the signal to watch for. + * \param func The signal dispatch function. + * \param data User data. + * \return A new signal event source. + * + * This function blocks the normal delivery of the given signal in the calling + * thread, and creates a "watch" for it. Signal delivery no longer happens + * asynchronously, but by wl_event_loop_dispatch() calling the dispatch + * callback function \c func. + * + * It is the caller's responsibility to ensure that all other threads have + * also blocked the signal. + * + * \sa wl_event_loop_signal_func_t + * \memberof wl_event_source + */ WL_EXPORT struct wl_event_source * wl_event_loop_add_signal(struct wl_event_loop *loop, int signal_number, @@ -275,15 +379,39 @@ wl_event_loop_add_signal(struct wl_event_loop *loop, return add_source(loop, &source->base, WL_EVENT_READABLE, data); } +/** \cond INTERNAL */ + struct wl_event_source_idle { struct wl_event_source base; wl_event_loop_idle_func_t func; }; +/** \endcond */ + struct wl_event_source_interface idle_source_interface = { NULL, }; +/** Create an idle task + * + * \param loop The event loop that will process the new task. + * \param func The idle task dispatch function. + * \param data User data. + * \return A new idle task (an event source). + * + * Idle tasks are dispatched before wl_event_loop_dispatch() goes to sleep. + * See wl_event_loop_dispatch() for more details. + * + * Idle tasks fire once, and are automatically destroyed right after the + * callback function has been called. + * + * An idle task can be cancelled before the callback has been called by + * wl_event_source_remove(). Calling wl_event_source_remove() after or from + * within the callback results in undefined behaviour. + * + * \sa wl_event_loop_idle_func_t + * \memberof wl_event_source + */ WL_EXPORT struct wl_event_source * wl_event_loop_add_idle(struct wl_event_loop *loop, wl_event_loop_idle_func_t func, @@ -307,12 +435,40 @@ wl_event_loop_add_idle(struct wl_event_loop *loop, return &source->base; } +/** Mark event source to be re-checked + * + * \param source The event source to be re-checked. + * + * This function permanently marks the event source to be re-checked after + * the normal dispatch of sources in wl_event_loop_dispatch(). Re-checking + * will keep iterating over all such event sources until the dispatch + * function for them all returns zero. + * + * Re-checking is used on sources that may become ready to dispatch as a + * side-effect of dispatching themselves or other event sources, including idle + * sources. Re-checking ensures all the incoming events have been fully drained + * before wl_event_loop_dispatch() returns. + * + * \memberof wl_event_source + */ WL_EXPORT void wl_event_source_check(struct wl_event_source *source) { wl_list_insert(source->loop->check_list.prev, &source->link); } +/** Remove an event source from its event loop + * + * \param source The event source to be removed. + * \return Zero. + * + * The event source is removed from the event loop it was created for, + * and is effectively destroyed. This invalidates \c source . + * The dispatch function of the source will no longer be called through this + * source. + * + * \memberof wl_event_source + */ WL_EXPORT int wl_event_source_remove(struct wl_event_source *source) { @@ -343,6 +499,20 @@ wl_event_loop_process_destroy_list(struct wl_event_loop *loop) wl_list_init(&loop->destroy_list); } +/** Create a new event loop context + * + * \return A new event loop context object. + * + * This creates a new event loop context. Initially this context is empty. + * Event sources need to be explicitly added to it. + * + * Normally the event loop is run by calling wl_event_loop_dispatch() in + * a loop until the program terminates. Alternatively, an event loop can be + * embedded in another event loop by its file descriptor, see + * wl_event_loop_get_fd(). + * + * \memberof wl_event_loop + */ WL_EXPORT struct wl_event_loop * wl_event_loop_create(void) { @@ -366,6 +536,19 @@ wl_event_loop_create(void) return loop; } +/** Destroy an event loop context + * + * \param loop The event loop to be destroyed. + * + * This emits the event loop destroy signal, closes the event loop file + * descriptor, and frees \c loop. + * + * If the event loop has existing sources, those cannot be safely removed + * afterwards. Therefore one must call wl_event_source_remove() on all + * event sources before destroying the event loop context. + * + * \memberof wl_event_loop + */ WL_EXPORT void wl_event_loop_destroy(struct wl_event_loop *loop) { @@ -391,6 +574,13 @@ post_dispatch_check(struct wl_event_loop *loop) return n; } +/** Dispatch the idle sources + * + * \param loop The event loop whose idle sources are dispatched. + * + * \sa wl_event_loop_add_idle() + * \memberof wl_event_loop + */ WL_EXPORT void wl_event_loop_dispatch_idle(struct wl_event_loop *loop) { @@ -404,6 +594,26 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop) } } +/** Wait for events and dispatch them + * + * \param loop The event loop whose sources to wait for. + * \param timeout The polling timeout in milliseconds. + * \return 0 for success, -1 for polling error. + * + * All the associated event sources are polled. This function blocks until + * any event source delivers an event (idle sources excluded), or the timeout + * expires. A timeout of -1 disables the timeout, causing the function to block + * indefinitely. A timeout of zero causes the poll to always return immediately. + * + * All idle sources are dispatched before blocking. An idle source is destroyed + * when it is dispatched. After blocking, all other ready sources are + * dispatched. Then, idle sources are dispatched again, in case the dispatched + * events created idle sources. Finally, all sources marked with + * wl_event_source_check() are dispatched in a loop until their dispatch + * functions all return zero. + * + * \memberof wl_event_loop + */ WL_EXPORT int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) { @@ -434,12 +644,36 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) return 0; } +/** Get the event loop file descriptor + * + * \param loop The event loop context. + * \return The aggregate file descriptor. + * + * This function returns the aggregate file descriptor, that represents all + * the event sources (idle sources excluded) associated with the given event + * loop context. When any event source makes an event available, it will be + * reflected in the aggregate file descriptor. + * + * When the aggregate file descriptor delivers an event, one can call + * wl_event_loop_dispatch() on the event loop context to dispatch all the + * available events. + * + * \memberof wl_event_loop + */ WL_EXPORT int wl_event_loop_get_fd(struct wl_event_loop *loop) { return loop->epoll_fd; } +/** Register a destroy listener for an event loop context + * + * \param loop The event loop context whose destruction to listen for. + * \param listener The listener with the callback to be called. + * + * \sa wl_listener + * \memberof wl_event_loop + */ WL_EXPORT void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, struct wl_listener *listener) @@ -447,10 +681,18 @@ wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, wl_signal_add(&loop->destroy_signal, listener); } +/** Get the listener struct for the specified callback + * + * \param loop The event loop context to inspect. + * \param notify The destroy callback to find. + * \return The wl_listener registered to the event loop context with + * the given callback pointer. + * + * \memberof wl_event_loop + */ WL_EXPORT struct wl_listener * wl_event_loop_get_destroy_listener(struct wl_event_loop *loop, wl_notify_func_t notify) { return wl_signal_get(&loop->destroy_signal, notify); } - diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 61da8ab7..fd458c56 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -43,11 +43,88 @@ enum { WL_EVENT_ERROR = 0x08 }; +/** File descriptor dispatch function type + * + * Functions of this type are used as callbacks for file descriptor events. + * + * \param fd The file descriptor delivering the event. + * \param mask Describes the kind of the event as a bitwise-or of: + * \c WL_EVENT_READABLE, \c WL_EVENT_WRITABLE, \c WL_EVENT_HANGUP, + * \c WL_EVENT_ERROR. + * \param data The user data argument of the related wl_event_loop_add_fd() + * call. + * \return If the event source is registered for re-check with + * wl_event_source_check(): 0 for all done, 1 for needing a re-check. + * If not registered, the return value is ignored and should be zero. + * + * \sa wl_event_loop_add_fd() + * \memberof wl_event_source + */ typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data); + +/** Timer dispatch function type + * + * Functions of this type are used as callbacks for timer expiry. + * + * \param data The user data argument of the related wl_event_loop_add_timer() + * call. + * \return If the event source is registered for re-check with + * wl_event_source_check(): 0 for all done, 1 for needing a re-check. + * If not registered, the return value is ignored and should be zero. + * + * \sa wl_event_loop_add_timer() + * \memberof wl_event_source + */ typedef int (*wl_event_loop_timer_func_t)(void *data); + +/** Signal dispatch function type + * + * Functions of this type are used as callbacks for (POSIX) signals. + * + * \param signal_number + * \param data The user data argument of the related wl_event_loop_add_signal() + * call. + * \return If the event source is registered for re-check with + * wl_event_source_check(): 0 for all done, 1 for needing a re-check. + * If not registered, the return value is ignored and should be zero. + * + * \sa wl_event_loop_add_signal() + * \memberof wl_event_source + */ typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data); + +/** Idle task function type + * + * Functions of this type are used as callbacks before blocking in + * wl_event_loop_dispatch(). + * + * \param data The user data argument of the related wl_event_loop_add_idle() + * call. + * + * \sa wl_event_loop_add_idle() wl_event_loop_dispatch() + * \memberof wl_event_source + */ typedef void (*wl_event_loop_idle_func_t)(void *data); +/** \struct wl_event_loop + * + * \brief An event loop context + * + * Usually you create an event loop context, add sources to it, and call + * wl_event_loop_dispatch() in a loop to process events. + * + * \sa wl_event_source + */ + +/** \struct wl_event_source + * + * \brief An abstract event source + * + * This is the generic type for fd, timer, signal, and idle sources. + * Functions that operate on specific source types must not be used with + * a different type, even if the function signature allows it. + */ + struct wl_event_loop * wl_event_loop_create(void); From 5bb82687667ed522615f3263a91c283ced4f7f6a Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 14 Sep 2017 18:32:18 +0100 Subject: [PATCH 0446/1152] build: remove wayland-version.h.in from EXTRA_DIST All the foo.in files are in the tarball, as long as their foo counterparts are listed in AC_CONFIG_FILES For example - *.pc.in, Makefile.in files, etc. Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index fdc56899..0eedb108 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,7 +118,6 @@ BUILT_SOURCES = \ CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db DISTCLEANFILES = src/wayland-version.h -EXTRA_DIST = src/wayland-version.h.in @@ -259,7 +258,7 @@ os_wrappers_test_LDADD = libtest-runner.la exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la -EXTRA_DIST += tests/scanner-test.sh \ +EXTRA_DIST = tests/scanner-test.sh \ tests/data/example.xml \ tests/data/example-client.h \ tests/data/example-server.h \ From f6bbc975d30560a4cd73038b1cca840d330ed428 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 29 Sep 2017 13:46:28 -0500 Subject: [PATCH 0447/1152] protocol: Suggest get_registry not be called frequently I've heard some complaints that wl_display.get_registry "leaks" server memory because wl_registry has no destructor. While this isn't strictly true - all those resources are freed when the client disconnects - it's a bit of a gotcha for neophytes. Since wl_registry's version is not requested in any way through wl_display.get_registry, we can't add a destructor request without breaking ABI. So let's be a little more clear about the result of getting too many wl_registry objects. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 29b63be7..aabc7aed 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -57,6 +57,12 @@ This request creates a registry object that allows the client to list and bind the global objects available from the compositor. + + It should be noted that the server side resources consumed in + response to a get_registry request can only be released when the + client disconnects, not when the client side proxy is destroyed. + Therefore, clients should invoke get_registry as infrequently as + possible to avoid wasting memory. From 242005636d0897db166215ed09cf3832217df008 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 8 Sep 2017 11:49:53 +0100 Subject: [PATCH 0448/1152] wayland-server: document WL_HIDE_DEPRECATED Add some inline information, what the macro is used for, why it came to be and what we shouldn't do if we consider further deprecation in the future deprecation. Cc: Pekka Paalanen Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- src/wayland-server.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/wayland-server.h b/src/wayland-server.h index f11fb4d0..ccf9783a 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -43,6 +43,16 @@ extern "C" { #endif +/* + * The user can set this macro to hide the wl_object, wl_resource and wl_buffer + * objects alongside the associated API. + * + * The structs were meant to be opaque, although we missed that in the early days. + * + * NOTE: the list of structs, functions, etc in this section MUST NEVER GROW. + * Otherwise we will break forward compatibility and applications that used to + * build fine will no longer be able to do so. + */ #ifndef WL_HIDE_DEPRECATED struct wl_object { From 5d201df72f3d4f4cb8b8f75f980169b03507da38 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Tue, 28 Nov 2017 21:38:07 +0100 Subject: [PATCH 0449/1152] cursor: Fix heap overflows when parsing malicious files. It is possible to trigger heap overflows due to an integer overflow while parsing images. The integer overflow occurs because the chosen limit 0x10000 for dimensions is too large for 32 bit systems, because each pixel takes 4 bytes. Properly chosen values allow an overflow which in turn will lead to less allocated memory than needed for subsequent reads. See also: https://cgit.freedesktop.org/xorg/lib/libXcursor/commit/?id=4794b5dd34688158fb51a2943032569d3780c4b8 Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=103961 Signed-off-by: Tobias Stoeckmann [Pekka: add link to the corresponding libXcursor commit] Signed-off-by: Pekka Paalanen --- cursor/xcursor.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index ca41c4ac..689c7026 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -202,6 +202,11 @@ XcursorImageCreate (int width, int height) { XcursorImage *image; + if (width < 0 || height < 0) + return NULL; + if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) + return NULL; + image = malloc (sizeof (XcursorImage) + width * height * sizeof (XcursorPixel)); if (!image) @@ -482,7 +487,8 @@ _XcursorReadImage (XcursorFile *file, if (!_XcursorReadUInt (file, &head.delay)) return NULL; /* sanity check data */ - if (head.width >= 0x10000 || head.height > 0x10000) + if (head.width > XCURSOR_IMAGE_MAX_SIZE || + head.height > XCURSOR_IMAGE_MAX_SIZE) return NULL; if (head.width == 0 || head.height == 0) return NULL; From 341bb12a0d6952ba7af840dabe9651ced582e7a7 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 14 Apr 2017 19:48:04 +0100 Subject: [PATCH 0450/1152] tests: Add one more indentation level to some macros This is a preparatory patch for the next one. Signed-off-by: Emmanuel Gil Peyrot Reviewed-by: Daniel Stone --- tests/test-runner.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/test-runner.h b/tests/test-runner.h index 64f8d4c6..c7a84aa9 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -37,24 +37,24 @@ struct test { int must_fail; } __attribute__ ((aligned (16))); -#define TEST(name) \ - static void name(void); \ - \ - const struct test test##name \ - __attribute__ ((section ("test_section"))) = { \ - #name, name, 0 \ - }; \ - \ +#define TEST(name) \ + static void name(void); \ + \ + const struct test test##name \ + __attribute__ ((section ("test_section"))) = { \ + #name, name, 0 \ + }; \ + \ static void name(void) -#define FAIL_TEST(name) \ - static void name(void); \ - \ - const struct test test##name \ - __attribute__ ((section ("test_section"))) = { \ - #name, name, 1 \ - }; \ - \ +#define FAIL_TEST(name) \ + static void name(void); \ + \ + const struct test test##name \ + __attribute__ ((section ("test_section"))) = { \ + #name, name, 1 \ + }; \ + \ static void name(void) int From 4c920f0f5e591b066544cfda5a2b223ef46334a0 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 14 Apr 2017 19:48:05 +0100 Subject: [PATCH 0451/1152] =?UTF-8?q?tests:=20Mark=20tests=20used=20so=20t?= =?UTF-8?q?hey=20don=E2=80=99t=20get=20removed=20at=20link=20time?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this attribute, these macros were making Weston’s tests fail to build with LTO enabled. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94602 Signed-off-by: Markus Trippelsdorf Signed-off-by: Emmanuel Gil Peyrot Tested-by: Emmanuel Gil Peyrot Reviewed-by: Daniel Stone --- tests/test-runner.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-runner.h b/tests/test-runner.h index c7a84aa9..81ed0343 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -41,7 +41,7 @@ struct test { static void name(void); \ \ const struct test test##name \ - __attribute__ ((section ("test_section"))) = { \ + __attribute__ ((used, section ("test_section"))) = { \ #name, name, 0 \ }; \ \ @@ -51,7 +51,7 @@ struct test { static void name(void); \ \ const struct test test##name \ - __attribute__ ((section ("test_section"))) = { \ + __attribute__ ((used, section ("test_section"))) = { \ #name, name, 1 \ }; \ \ From 2f392daadbf27fbd91907e27c3333af41ca15765 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 12 Oct 2017 13:39:17 +0100 Subject: [PATCH 0452/1152] cursor: add forward declaration for struct wl_buffer This makes the header self-contained, since the struct is considered opaque from waylad-cursor POV. As we're here move the wl_shm fwd. declaration alongside the others. Making it easier to read and track. Signed-off-by: Emil Velikov Reviewed-by: Yong Bakos --- cursor/wayland-cursor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h index 09a13a7b..40d3fc5c 100644 --- a/cursor/wayland-cursor.h +++ b/cursor/wayland-cursor.h @@ -33,6 +33,8 @@ extern "C" { #endif struct wl_cursor_theme; +struct wl_buffer; +struct wl_shm; struct wl_cursor_image { uint32_t width; /* actual width */ @@ -48,8 +50,6 @@ struct wl_cursor { char *name; }; -struct wl_shm; - struct wl_cursor_theme * wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm); From 698dde195837f3d0844b2725ba4ea8ce9ee7518c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 2 Dec 2017 10:57:45 +0800 Subject: [PATCH 0453/1152] protocol: Add deprecation note about wl_shell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that xdg_shell is stable and much better defined than wl_shell we can finally deprecate wl_shell and guide users towards xdg_shell instead. Signed-off-by: Jonas Ådahl Acked-by: Pekka Paalanen Reviewed-by: Daniel Stone --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index aabc7aed..77d991e2 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -976,6 +976,9 @@ It allows clients to associate a wl_shell_surface with a basic surface. + + Note! This protocol is deprecated and not intended for production use. + For desktop-style user interfaces, use xdg_shell. From ed7ad31ac2fa3fb1aa03ed1435e6673b6b070f55 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Mon, 28 Aug 2017 18:03:38 +1000 Subject: [PATCH 0454/1152] eventloop: clarify post_dispatch_check() This *technically* changes the semantics of the return value of the source callbacks. Previously you could return a negative number from a source callback and it would prevent *other* source callbacks from triggering a subsequent recheck. Doing that seems like such a bad idea it's not worth supporting. v2: Log this case if it is hit, so we don't silently change behaviour. Signed-off-by: Christopher James Halse Rogers Reviewed-by: Daniel Stone --- src/event-loop.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index 49e48bf4..eb2dce63 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -559,19 +560,26 @@ wl_event_loop_destroy(struct wl_event_loop *loop) free(loop); } -static int +static bool post_dispatch_check(struct wl_event_loop *loop) { struct epoll_event ep; struct wl_event_source *source, *next; - int n; + bool needs_recheck = false; ep.events = 0; - n = 0; - wl_list_for_each_safe(source, next, &loop->check_list, link) - n += source->interface->dispatch(source, &ep); + wl_list_for_each_safe(source, next, &loop->check_list, link) { + int dispatch_result; - return n; + dispatch_result = source->interface->dispatch(source, &ep); + if (dispatch_result < 0) { + wl_log("Source dispatch function returned negative value!"); + wl_log("This would previously accidentally suppress a follow-up dispatch"); + } + needs_recheck |= dispatch_result != 0; + } + + return needs_recheck; } /** Dispatch the idle sources @@ -619,7 +627,7 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) { struct epoll_event ep[32]; struct wl_event_source *source; - int i, count, n; + int i, count; wl_event_loop_dispatch_idle(loop); @@ -637,9 +645,7 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) wl_event_loop_dispatch_idle(loop); - do { - n = post_dispatch_check(loop); - } while (n > 0); + while (post_dispatch_check(loop)); return 0; } From c3ff179a953213ed4dd91b96bd1c093b4a7d460e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armin=20Krezovi=C4=87?= Date: Thu, 27 Jul 2017 14:08:37 +0200 Subject: [PATCH 0455/1152] Do not create man page links with doxygen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a lot of files created with .so links to non-installed files, making most of installed pages useless. The files referenced in .so links are not suitable for installation nor do they contain any useful information for them to be worth fixing. Signed-off-by: Armin Krezović Acked-by: Daniel Stone --- doc/doxygen/wayland.doxygen.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in index 3913a135..60c5fbbb 100644 --- a/doc/doxygen/wayland.doxygen.in +++ b/doc/doxygen/wayland.doxygen.in @@ -7,7 +7,7 @@ TAB_SIZE = 8 QUIET = YES HTML_TIMESTAMP = YES GENERATE_LATEX = NO -MAN_LINKS = YES +MAN_LINKS = NO PREDEFINED = WL_EXPORT= \ WL_PRINTF(x,y)= MACRO_EXPANSION = YES From 971a9e7873e43f3bd059b340e1e9bfa65b384e47 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 13 Apr 2017 11:51:43 -0500 Subject: [PATCH 0456/1152] connection: close_fds() should only remove fds it closed from the buffer All current callers close all fds, so this has gone unnoticed, but if we close less than all fds with close_fds() we leak all the unclosed ones and ruin further event demarshalling. A future patch will close less than the full buffer's worth of fds, so this is now noticed. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/connection.c b/src/connection.c index 5c3d187c..7fe35b5e 100644 --- a/src/connection.c +++ b/src/connection.c @@ -186,6 +186,7 @@ close_fds(struct wl_buffer *buffer, int max) count = size / sizeof fds[0]; if (max > 0 && max < count) count = max; + size = count * sizeof fds[0]; for (i = 0; i < count; i++) close(fds[i]); buffer->tail += size; From 56696e514842d214be492c3291e7572f2d70d976 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 13 Apr 2017 11:51:47 -0500 Subject: [PATCH 0457/1152] client: Simplify some logic in queue_event Both the blocks in this if/else clause do the same thing, so combine the comparisons into one. No functional change. Signed-off-by: Derek Foreman Reviewed-by: Bryce Harrington Reviewed-by: Daniel Stone --- src/wayland-client.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 3d7361ea..8fb2dbd3 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1228,10 +1228,7 @@ queue_event(struct wl_display *display, int len) return 0; proxy = wl_map_lookup(&display->objects, id); - if (proxy == WL_ZOMBIE_OBJECT) { - wl_connection_consume(display->connection, size); - return size; - } else if (proxy == NULL) { + if (!proxy || proxy == WL_ZOMBIE_OBJECT) { wl_connection_consume(display->connection, size); return size; } From a46d89de9aaad325ea908a39a1a58edfabc95918 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 13 Apr 2017 11:51:51 -0500 Subject: [PATCH 0458/1152] connection: Use wl_buffer_size() for all buffer size calculations There were two places where we did the same calculation manually. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index 7fe35b5e..e60ad75f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -178,7 +178,7 @@ close_fds(struct wl_buffer *buffer, int max) int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count; size_t size; - size = buffer->head - buffer->tail; + size = wl_buffer_size(buffer); if (size == 0) return; @@ -222,7 +222,7 @@ build_cmsg(struct wl_buffer *buffer, char *data, int *clen) struct cmsghdr *cmsg; size_t size; - size = buffer->head - buffer->tail; + size = wl_buffer_size(buffer); if (size > MAX_FDS_OUT * sizeof(int32_t)) size = MAX_FDS_OUT * sizeof(int32_t); From 8d4250ab5e2cf091edf56085def9eaa73752aa9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 11 Oct 2017 17:31:33 +0800 Subject: [PATCH 0459/1152] scanner: Add --strict flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a --strict flag for making wayland-scanner fail if the DTD verification fails. This is useful for testing, so that a test case can fail a scan when the protocol doesn't comply with the DTD. Signed-off-by: Jonas Ådahl --- src/scanner.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index c345ed6b..1308fc7c 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -72,7 +72,9 @@ usage(int ret) " the scanner was built against.\n" " -c, --include-core-only include the core version of the headers,\n" " that is e.g. wayland-client-core.h instead\n" - " of wayland-client.h.\n"); + " of wayland-client.h.\n" + " -s, --strict exit immediately with an error if DTD\n" + " verification fails.\n"); exit(ret); } @@ -1801,6 +1803,7 @@ int main(int argc, char *argv[]) bool help = false; bool core_headers = false; bool version = false; + bool strict = false; bool fail = false; int opt; enum { @@ -1813,11 +1816,12 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "include-core-only", no_argument, NULL, 'c' }, + { "strict", no_argument, NULL, 's' }, { 0, 0, NULL, 0 } }; while (1) { - opt = getopt_long(argc, argv, "hvc", options, NULL); + opt = getopt_long(argc, argv, "hvcs", options, NULL); if (opt == -1) break; @@ -1832,6 +1836,9 @@ int main(int argc, char *argv[]) case 'c': core_headers = true; break; + case 's': + strict = true; + break; default: fail = true; break; @@ -1894,6 +1901,10 @@ int main(int argc, char *argv[]) "* WARNING: XML failed validation against built-in DTD *\n" "* *\n" "*******************************************************\n"); + if (strict) { + fclose(input); + exit(EXIT_FAILURE); + } } /* create XML parser */ From de24f4dd76652e11b552e61eb715285b9123b1d1 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 9 May 2016 14:45:05 +0300 Subject: [PATCH 0460/1152] protocol: make get_subsurface double-buffered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing specification was not explicitly clear on when wl_subcompositor.get_subsurface request actually adds the sub-surface to the parent in the compositor's scenegraph. The implicit assumption was that this happens immediately, but it was not written anywhere. If it happens immediately, the client doing things in a wrong order may cause a glitch on screen. Particularly, if the wl_surface B that is going to be a sub-surface for wl_surface A (the parent) already has a buffer committed, and the parent surface is mapped, then get_subsurface will (may?) cause wl_surface B to become mapped immediately. That leaves no time to set up the sub-surface z-order or position before mapping, hence there can be a visible glitch. The way to avoid that, given that the parent surface is mapped, is to not commit a buffer to wl_surface B until all the sub-surface setup is done. However, doing the sub-surface setup always requires a wl_surface.commit on the parent surface unless the defaults happen to be correct. To make setting up a subsurface slightly easier by removing one possibility for a glitch, this patch amends the specification to require a wl_surface.commit on the parent surface for get_subsurface to complete. The sub-surface cannot become mapped before a parent commit. This change may break existing clients that relied on the glitchy sequence to not need a parent surface commit to map the sub-surface. However, presumably all uses would at least issue a wl_subsurface.set_position, which requires a parent surface commit to apply. That would guarantee that there is a parent surface commit after get_subsurface, and so reduces the chances of breaking anything. In other cases, this change may simply remove a possibility for the glitch. This patch also adds a note about changing wl_surface.commit behaviour on wl_subcompositor.get_subsurface. (That could be a separate patch.) The behaviour of wl_subsurface.destroy remains as specified, even though it is now slightly asymmetrical to get_subsurface. This is emphasized by adding the word "immediately". The effects of destruction were already explicitly documented, as is the way to achieve synchronized unmapping, so changing destruction behaviour would likely be more disruptive, and also open up more corner cases (what would happen between destroy and unmapping?). Bug: https://phabricator.freedesktop.org/T7358 Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone Reviewed-by: Derek Foreman Reviewed-by: Jonas Ådahl Reviewed-by: Martin Gräßlin --- protocol/wayland.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 77d991e2..b5662e02 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2577,6 +2577,14 @@ The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise a protocol error is raised. + + Adding sub-surfaces to a parent is a double-buffered operation on the + parent (see wl_surface.commit). The effect of adding a sub-surface + becomes visible on the next time the state of the parent surface is + applied. + + This request modifies the behaviour of wl_surface.commit request on + the sub-surface, see the documentation on wl_subsurface interface. @@ -2646,7 +2654,7 @@ that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted, and the wl_surface loses its role as - a sub-surface. The wl_surface is unmapped. + a sub-surface. The wl_surface is unmapped immediately.
From 1b6521e695de79a838c75e6bc5feba85e8aab13a Mon Sep 17 00:00:00 2001 From: Matt Hoosier Date: Mon, 27 Nov 2017 08:54:54 -0600 Subject: [PATCH 0461/1152] client: Allow absolute paths in WAYLAND_DISPLAY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to support system compositor instances, it is necessary to allow clients' wl_display_connect() to find the compositor's listening socket somewhere outside of XDG_RUNTIME_DIR. For a full account, see the discussion beginning here: https://lists.freedesktop.org/archives/wayland-devel/2017-November/035664.html This change adjusts the client-side connection logic so that, if WAYLAND_DISPLAY is formatted as an absolute pathname, the socket connection attempt is made to just $WAYLAND_DISPLAY rather than usual user-private location $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY. This change is based on Davide Bettio's submission of the same concept at: https://lists.freedesktop.org/archives/wayland-devel/2015-August/023838.html. v4 changes: * Improved internal comments and some boundary-condition error checks in test case. * Refer to compositor as "Wayland server" rather than "Wayland display" in wl_display_connect() doxygen comments. * Remove redundant descriptions of parameter-interpretation mechanics from wl_display_connect() manpage. Reworked things to make it clear that 'name' and $WAYLAND_DISLAY are each capable of encoding absolute server socket paths. * Remove callout to reference implementation behavior in protocol documented. In its place there is now a simple statement that implementations can optionally support absolute socket paths. v3 changes: * Added test case. * Clarified documentation to note that 'name' parameter to wl_display_connect() can also be an absolute path. v2 changes: * Added backward incompatibility note to wl_display_connect() manpage. * Rephased wl_display_connect() manpage changes to precisely match actual changed behavior. * Added mention of new absolute path behavior in wl_display_connect() doxygen comments. * Mentioned new absolute path interpretation of WAYLAND_DISPLAY in protocol documentation. Signed-off-by: Matt Hoosier Acked-by: Jonas Ådahl Reviewed-by: Pekka Paalanen --- doc/man/wl_display_connect.xml | 32 +++++++-- doc/publican/sources/Protocol.xml | 5 +- src/wayland-client.c | 47 ++++++++++--- tests/socket-test.c | 109 ++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 16 deletions(-) diff --git a/doc/man/wl_display_connect.xml b/doc/man/wl_display_connect.xml index 7e6e05c6..dab4ddba 100644 --- a/doc/man/wl_display_connect.xml +++ b/doc/man/wl_display_connect.xml @@ -55,15 +55,39 @@ Description wl_display_connect connects to a Wayland socket that was previously opened by a Wayland server. The server socket must - be placed in XDG_RUNTIME_DIR for this function to - find it. The name argument specifies the name of + be placed in XDG_RUNTIME_DIR when WAYLAND_DISPLAY + (or name, see below) is a simple name, for this + function to find it. The server socket is also allowed to exist at an + arbitrary path; usage details follow. See below for compatibility issue + details. + + The name argument specifies the name of the socket or NULL to use the default (which is "wayland-0"). The environment variable - WAYLAND_DISPLAY replaces the default value. If - WAYLAND_SOCKET is set, this function behaves like + WAYLAND_DISPLAY replaces the default value. + + If name is an absolute path, then that path is used + as the Wayland socket to which the connection is attempted. Note that + in combination with the default-value behavior described above, this + implies that setting WAYLAND_DISPLAY to an absolute + path will implicitly cause name to take on that + absolute path if name is NULL. + + If WAYLAND_SOCKET is set, this function behaves like wl_display_connect_to_fd with the file-descriptor number taken from the environment variable. + Support for interpreting WAYLAND_DISPLAY as an + absolute path is a change in behavior compared to + wl_display_connect's behavior in versions + 1.14 and older of Wayland. It is no longer guaranteed in versions + 1.15 and higher that the Wayland socket chosen is equivalent to + manually constructing a socket pathname by concatenating + XDG_RUNTIME_DIR and WAYLAND_DISPLAY. + Manual construction of the socket path must account for the + possibility that WAYLAND_DISPLAY contains an absolute + path. + wl_display_connect_to_fd connects to a Wayland socket with an explicit file-descriptor. The file-descriptor is passed as argument fd. diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index ba6b5f1e..9fdee9a7 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -94,7 +94,10 @@ The protocol is sent over a UNIX domain stream socket, where the endpoint usually is named wayland-0 (although it can be changed via WAYLAND_DISPLAY - in the environment). + in the environment). Beginning in Wayland 1.15, implementations can + optionally support server socket endpoints located at arbitrary + locations in the filesystem by setting WAYLAND_DISPLAY + to the absolute path at which the server endpoint listens. Every message is structured as 32-bit words; values are represented in the diff --git a/src/wayland-client.c b/src/wayland-client.c index 8fb2dbd3..795b4e9e 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -857,9 +857,17 @@ connect_to_socket(const char *name) socklen_t size; const char *runtime_dir; int name_size, fd; + bool path_is_absolute; + + if (name == NULL) + name = getenv("WAYLAND_DISPLAY"); + if (name == NULL) + name = "wayland-0"; + + path_is_absolute = name[0] == '/'; runtime_dir = getenv("XDG_RUNTIME_DIR"); - if (!runtime_dir) { + if (!runtime_dir && !path_is_absolute) { wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n"); /* to prevent programs reporting * "failed to create display: Success" */ @@ -867,25 +875,32 @@ connect_to_socket(const char *name) return -1; } - if (name == NULL) - name = getenv("WAYLAND_DISPLAY"); - if (name == NULL) - name = "wayland-0"; - fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); if (fd < 0) return -1; memset(&addr, 0, sizeof addr); addr.sun_family = AF_LOCAL; - name_size = - snprintf(addr.sun_path, sizeof addr.sun_path, - "%s/%s", runtime_dir, name) + 1; + if (!path_is_absolute) { + name_size = + snprintf(addr.sun_path, sizeof addr.sun_path, + "%s/%s", runtime_dir, name) + 1; + } else { + /* absolute path */ + name_size = + snprintf(addr.sun_path, sizeof addr.sun_path, + "%s", name) + 1; + } assert(name_size > 0); if (name_size > (int)sizeof addr.sun_path) { - wl_log("error: socket path \"%s/%s\" plus null terminator" - " exceeds 108 bytes\n", runtime_dir, name); + if (!path_is_absolute) { + wl_log("error: socket path \"%s/%s\" plus null terminator" + " exceeds %i bytes\n", runtime_dir, name, (int) sizeof(addr.sun_path)); + } else { + wl_log("error: socket path \"%s\" plus null terminator" + " exceeds %i bytes\n", name, (int) sizeof(addr.sun_path)); + } close(fd); /* to prevent programs reporting * "failed to add socket: Success" */ @@ -994,6 +1009,16 @@ wl_display_connect_to_fd(int fd) * its value will be replaced with the WAYLAND_DISPLAY environment * variable if it is set, otherwise display "wayland-0" will be used. * + * If \c name is an absolute path, then that path is used as-is for + * the location of the socket at which the Wayland server is listening; + * no qualification inside XDG_RUNTIME_DIR is attempted. + * + * If \c name is \c NULL and the WAYLAND_DISPLAY environment variable + * is set to an absolute pathname, then that pathname is used as-is + * for the socket in the same manner as if \c name held an absolute + * path. Support for absolute paths in \c name and WAYLAND_DISPLAY + * is present since Wayland version 1.15. + * * \memberof wl_display */ WL_EXPORT struct wl_display * diff --git a/tests/socket-test.c b/tests/socket-test.c index bb034f43..e9705628 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -26,10 +26,14 @@ #include #include #include +#include +#include +#include #include #include #include "wayland-client.h" +#include "wayland-os.h" #include "wayland-server.h" #include "test-runner.h" @@ -173,3 +177,108 @@ TEST(add_socket_auto) wl_display_destroy(d); } + +struct client_create_listener { + struct wl_listener listener; + struct wl_display *display; +}; + +struct client_destroy_listener { + struct wl_listener listener; + struct wl_display *display; +}; + +static void +client_destroy_notify(struct wl_listener *l, void *data) +{ + struct client_destroy_listener *listener = + wl_container_of(l, listener, listener); + wl_display_terminate(listener->display); + free(listener); +} + +static void +client_create_notify(struct wl_listener *l, void *data) +{ + struct wl_client *client = data; + struct client_create_listener *listener = + wl_container_of(l, listener, listener); + struct client_destroy_listener *destroy_listener = (struct client_destroy_listener *)malloc(sizeof *destroy_listener); + assert(destroy_listener != NULL); + destroy_listener->display = listener->display; + destroy_listener->listener.notify = client_destroy_notify; + wl_client_add_destroy_listener(client, &destroy_listener->listener); +} + +TEST(absolute_socket_path) +{ + struct wl_display *display; + struct client_create_listener client_create_listener; + struct sockaddr_un addr; + int fd; + socklen_t size; + const char *xdg_runtime_dir; + size_t len; + int ret; + pid_t pid; + + /* It's a little weird that this test about absolute socket paths + * uses XDG_RUNTIME_DIR, but that's the only location guaranteed + * by test-runner to be both writable and unique. This isn't + * really a problem; we'll just take care that the leaf-level + * filename used for the socket isn't anything that would + * accidentally be generated by a default usage of wl_display_connect(). */ + xdg_runtime_dir = require_xdg_runtime_dir(); + memset(&addr, 0, sizeof addr); + len = snprintf(addr.sun_path, sizeof addr.sun_path, + "%s/%s", xdg_runtime_dir, "wayland-absolute-0"); + assert(len < sizeof addr.sun_path + && "Bug in test. Path too long"); + + /* The path must not exist prior to binding. */ + assert(access(addr.sun_path, F_OK) == -1); + + size = offsetof (struct sockaddr_un, sun_path) + strlen(addr.sun_path); + addr.sun_family = AF_LOCAL; + fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); + assert(fd >= 0 ); + ret = bind(fd, (struct sockaddr *) &addr, size); + assert(ret >= 0); + ret = listen(fd, 128); + assert(ret >= 0); + + /* Start server display. Be careful (by avoiding wl_display_add_socket_auto() + * to offer only the absolutely qualified socket made above. */ + display = wl_display_create(); + assert(display != NULL); + client_create_listener.listener.notify = client_create_notify; + client_create_listener.display = display; + wl_display_add_client_created_listener(display, &client_create_listener.listener); + ret = wl_display_add_socket_fd(display, fd); + assert(ret == 0); + + /* Execute client that connects to the absolutely qualified server socket path. */ + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + ret = setenv("WAYLAND_DISPLAY", addr.sun_path, 1); + assert(ret == 0); + struct wl_display *client_display = wl_display_connect(NULL); + assert(client_display != NULL); + ret = wl_display_roundtrip(client_display); + assert(ret != -1); + wl_display_disconnect(client_display); + exit(0); + assert(false); + } + + wl_display_run(display); + ret = waitpid(pid, NULL, 0); + assert(ret == pid); + + wl_display_destroy(display); + + ret = unlink(addr.sun_path); + assert(ret == 0); +} From 147617800dd615b72a7449c9fd591ec0c7cf33af Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 21 Nov 2016 12:09:46 +0200 Subject: [PATCH 0462/1152] doc: start documenting Xwayland MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a rough intro to what Xwayland is and does, with just one implementation detail so far (Window identification). I paid no attention to formatting details, those can be polished in follow-ups. I just want the prose out. I also just quickly whacked up the diagram, would be happy to see someone replace it with a nicer one. I just didn't have time to learn dot for now. v2: - typo fix - rephrase "talking to hardware" as "driving the displays" - mention circular dependency in intro - add section to explain rootless and rootful modes - remove paragraph about Xwayland protocol usage - move TBD part to the end under a new section header v3: - use "advantage" and "disadvantage" instead of "pro" and "con" - slight rewording on rootful mode and rootless mode paragraphs - removed the paragraph about the lack of shell and special Wayland protocol extensions - removed the commented out list of ideas to write v4: - typo fixes pointed out by Yong Cc: Olivier Fourdan Cc: Jonas Ådahl Cc: Daniel Stone Signed-off-by: Pekka Paalanen Reviewed-by: Jonas Ådahl --- doc/publican/Makefile.am | 5 +- doc/publican/sources/Wayland.xml | 1 + doc/publican/sources/Xwayland.xml | 170 ++++++++++++++++++ .../sources/images/xwayland-architecture.png | Bin 0 -> 7611 bytes 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 doc/publican/sources/Xwayland.xml create mode 100644 doc/publican/sources/images/xwayland-architecture.png diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am index 57728a00..e861fe67 100644 --- a/doc/publican/Makefile.am +++ b/doc/publican/Makefile.am @@ -24,9 +24,11 @@ publican_sources = \ $(srcdir)/sources/Preface.xml \ $(srcdir)/sources/Revision_History.xml \ $(srcdir)/sources/Protocol.xml \ + $(srcdir)/sources/Xwayland.xml \ $(srcdir)/sources/Compositors.xml \ $(srcdir)/sources/images/icon.svg \ $(srcdir)/sources/images/wayland.png \ + $(srcdir)/sources/images/xwayland-architecture.png \ $(srcdir)/sources/Client.xml \ $(srcdir)/sources/Server.xml @@ -43,7 +45,8 @@ css_sources = \ img_sources = \ $(srcdir)/sources/images/icon.svg \ - $(srcdir)/sources/images/wayland.png + $(srcdir)/sources/images/wayland.png \ + $(srcdir)/sources/images/xwayland-architecture.png doxygen_img_sources := \ $(doxydir)/xml/wayland-architecture.png \ diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/sources/Wayland.xml index 2f47f132..0457c15c 100644 --- a/doc/publican/sources/Wayland.xml +++ b/doc/publican/sources/Wayland.xml @@ -11,6 +11,7 @@ + diff --git a/doc/publican/sources/Xwayland.xml b/doc/publican/sources/Xwayland.xml new file mode 100644 index 00000000..a39866f8 --- /dev/null +++ b/doc/publican/sources/Xwayland.xml @@ -0,0 +1,170 @@ + + +%BOOK_ENTITIES; +]> + + X11 Application Support +
+ Introduction + + Being able to run existing X11 applications is crucial for the adoption + of Wayland, especially on desktops, as there will always be X11 + applications that have not been or cannot be converted into Wayland + applications, and throwing them all away would be prohibitive. + Therefore a Wayland compositor often needs to support running X11 + applications. + + + X11 and Wayland are different enough that there is no "simple" way to + translate between them. Most of X11 is uninteresting to a Wayland + compositor. That, combined with the gigantic implementation effort needed + to support X11, makes it intractable to just write X11 support directly in + a Wayland compositor. The implementation would be nothing short of a + real X11 server. + + + Therefore, Wayland compositors should use Xwayland, the X11 server that + lives in the Xorg server source code repository and shares most of the + implementation with the Xorg server. Xwayland is a complete X11 server, + just like Xorg is, but instead of driving the displays and opening input + devices, it acts as a Wayland client. The rest of this chapter talks + about how Xwayland works. + + + For integration and architecture reasons, while Xwayland is a Wayland + client of the Wayland compositor, the Wayland compositor is an X11 client + of Xwayland. This circular dependency requires special care from the + Wayland compositor. + +
+
+ Two Modes for Foreign Windows + + In general, windows from a foreign window system can be presented in one + of two ways: rootless and rootful (not rootless). + + + In rootful mode, the foreign window system as a whole is represented as a + window (or more) of its own. You have a native window, inside which all + the foreign windows are. The advantage of this approach in Xwayland's + case is that you can run your favourite X11 window manager to manage your + X11 applications. The disadvantage is that the foreign windows do not + integrate with the native desktop. Therefore this mode is not usually + used. + + + In rootless mode, each foreign window is a first-class resident among the + native windows. Foreign windows are not confined inside a native window + but act as if they were native windows. The advantage is that one can + freely stack and mix native and foreign windows, which is not possible in + rootful mode. The disadvantage is that this mode is harder to implement + and fundamental differences in window systems may prevent some things + from working. With rootless Xwayland, the Wayland compositor must take + the role as the X11 window manager, and one cannot use any other X11 + window manager in its place. + + + This chapter concentrates on the rootless mode, and ignores the rootful + mode. + +
+
+ Architecture + + A Wayland compositor usually takes care of launching Xwayland. + Xwayland works in cooperation with a Wayland compositor as follows: + +
+ Xwayland architecture diagram + + + + + + + +
+ + An X11 application connects to Xwayland just like it would connect to any + X server. Xwayland processes all the X11 requests. On the other end, + Xwayland is a Wayland client that connects to the Wayland compositor. + + + The X11 window manager (XWM) is an integral part of the Wayland + compositor. XWM uses the usual X11 window management protocol to manage + all X11 windows in Xwayland. Most importantly, XWM acts as a bridge + between Xwayland window state and the Wayland compositor's window manager + (WWM). This way WWM can manage all windows, both native Wayland and X11 + (Xwayland) windows. This is very important for a coherent user + experience. + + + Since Xwayland uses Wayland for input and output, it does not have any + use for the device drivers that Xorg uses. None of the xf86-video-* or + xf86-input-* modules are used. There also is no configuration file for + the Xwayland server. For optional hardware accelerated rendering, + Xwayland uses GLAMOR. + + + A Wayland compositor usually spawns only one Xwayland instance. This is + because many X11 applications assume they can communicate with other X11 + applications through the X server, and this requires a shared X server + instance. This also means that Xwayland does not protect nor isolate X11 + clients from each other, unless the Wayland compositor specifically + chooses to break the X11 client intercommunications by spawning + application specific Xwayland instances. X11 clients are naturally + isolated from Wayland clients. + + + Xwayland compatibility compared to a native X server will probably never + reach 100%. Desktop environment (DE) components, specifically X11 window + managers, are practically never supported. An X11 window manager would + not know about native Wayland windows, so it could manage only X11 + windows. On the other hand, there must be an XWM that reserves the + exclusive window manager role so that the Wayland compositor could show + the X11 windows appropriately. For other DE components, like pagers and + panels, adding the necessary interfaces to support them in WWM through XWM + is often considered not worthwhile. + +
+
+ X Window Manager (XWM) + + From the X11 point of view, the X window manager (XWM) living inside a + Wayland compositor is just like any other window manager. The difference + is mostly in which process it resides in, and the few extra conventions + in the X11 protocol to support Wayland window management (WWM) + specifically. + + + There are two separate asynchronous communication channels between + Xwayland and a Wayland compositor: one uses the Wayland protocol, and the + other one, solely for XWM, uses X11 protocol. This setting demands great + care from the XWM implementation to avoid (random) deadlocks with + Xwayland. It is often nearly impossible to prove that synchronous or + blocking X11 calls from XWM cannot cause a deadlock, and therefore it is + strongly recommended to make all X11 communications asynchronous. All + Wayland communications are already asynchonous by design. + +
+ Window identification + + In Xwayland, an X11 window may have a corresponding wl_surface object + in Wayland. The wl_surface object is used for input and output: it is + referenced by input events and used to provide the X11 window content + to the Wayland compositor. The X11 window and the wl_surface live in + different protocol streams, and they need to be matched for XWM to do + its job. + + + When Xwayland creates a wl_surface on Wayland, it will also send an X11 + ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying + the wl_surface Wayland object ID as the first 32-bit data element. This + is how XWM can associate a wl_surface with an X11 window. Note that + the request to create a wl_surface and the ID message may arrive in any + order in the Wayland compositor. + +
+
+
diff --git a/doc/publican/sources/images/xwayland-architecture.png b/doc/publican/sources/images/xwayland-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..f24dc1837f2e190c9d38719420a844aeb5997efa GIT binary patch literal 7611 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 literal 0 HcmV?d00001 From 9a2735c2b74d63e7495268e3c9595912d00314c8 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:16 -0600 Subject: [PATCH 0463/1152] connection: Don't declare a local variable just to takes its size We can sizeof the struct type instead of declaring a pointer and taking the size of what it points to. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index e60ad75f..d029914a 100644 --- a/src/connection.c +++ b/src/connection.c @@ -632,7 +632,7 @@ wl_connection_demarshal(struct wl_connection *connection, const char *signature; struct argument_details arg; struct wl_closure *closure; - struct wl_array *array, *array_extra; + struct wl_array *array_extra; count = arg_count_for_signature(message->signature); if (count > WL_CLOSURE_MAX_ARGS) { @@ -643,7 +643,8 @@ wl_connection_demarshal(struct wl_connection *connection, } num_arrays = wl_message_count_arrays(message); - closure = malloc(sizeof *closure + size + num_arrays * sizeof *array); + closure = malloc(sizeof *closure + size + + num_arrays * sizeof(struct wl_array)); if (closure == NULL) { errno = ENOMEM; wl_connection_consume(connection, size); From 383b2d965adf5b70330aa8165b395a85eb33e1df Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:17 -0600 Subject: [PATCH 0464/1152] server: Log closure before sending it This seems foolishly cosmetic on the surface - and will reorder log messages in certain failure cases. "request could not be marshalled" will now appear after logging the request that failed to marshal instead of before. The real point of this is that a follow up patch will make wl_closure_send() set fds to -1 as it buffers them for send, so they can be more easily cleaned up. Doing that while leaving this order unchanged would result in printing -1 for fds instead of their value. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/wayland-server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 82a3b01f..61e03150 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -220,11 +220,11 @@ handle_array(struct wl_resource *resource, uint32_t opcode, return; } + log_closure(resource, closure, true); + if (send_func(closure, resource->client->connection)) resource->client->error = 1; - log_closure(resource, closure, true); - wl_closure_destroy(closure); } From e802094c9b6927148d1a7249af9ead49673f22b9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:18 -0600 Subject: [PATCH 0465/1152] connection: Refactor out closure allocation Moves the common/similar bits into one place. This has a minor functional change - count and message are now initialized immediately, previously they'd only be set if (de)marshal was successful. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 73 ++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/src/connection.c b/src/connection.c index d029914a..8d8eb60c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -524,6 +524,42 @@ wl_argument_from_va_list(const char *signature, union wl_argument *args, } } +static struct wl_closure * +wl_closure_init(const struct wl_message *message, uint32_t size, + int *num_arrays, union wl_argument *args) +{ + struct wl_closure *closure; + int count; + + count = arg_count_for_signature(message->signature); + if (count > WL_CLOSURE_MAX_ARGS) { + wl_log("too many args (%d)\n", count); + errno = EINVAL; + return NULL; + } + + if (size) { + *num_arrays = wl_message_count_arrays(message); + closure = malloc(sizeof *closure + size + + *num_arrays * sizeof(struct wl_array)); + } else { + closure = malloc(sizeof *closure); + } + + if (!closure) { + errno = ENOMEM; + return NULL; + } + + if (args) + memcpy(closure->args, args, count * sizeof *args); + + closure->message = message; + closure->count = count; + + return closure; +} + struct wl_closure * wl_closure_marshal(struct wl_object *sender, uint32_t opcode, union wl_argument *args, @@ -535,20 +571,11 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, const char *signature; struct argument_details arg; - count = arg_count_for_signature(message->signature); - if (count > WL_CLOSURE_MAX_ARGS) { - wl_log("too many args (%d)\n", count); - errno = EINVAL; + closure = wl_closure_init(message, 0, NULL, args); + if (closure == NULL) return NULL; - } - closure = malloc(sizeof *closure); - if (closure == NULL) { - errno = ENOMEM; - return NULL; - } - - memcpy(closure->args, args, count * sizeof *args); + count = closure->count; signature = message->signature; for (i = 0; i < count; i++) { @@ -593,8 +620,6 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, closure->sender_id = sender->id; closure->opcode = opcode; - closure->message = message; - closure->count = count; return closure; @@ -628,28 +653,19 @@ wl_connection_demarshal(struct wl_connection *connection, uint32_t *p, *next, *end, length, id; int fd; char *s; - unsigned int i, count, num_arrays; + int i, count, num_arrays; const char *signature; struct argument_details arg; struct wl_closure *closure; struct wl_array *array_extra; - count = arg_count_for_signature(message->signature); - if (count > WL_CLOSURE_MAX_ARGS) { - wl_log("too many args (%d)\n", count); - errno = EINVAL; + closure = wl_closure_init(message, size, &num_arrays, NULL); + if (closure == NULL) { wl_connection_consume(connection, size); return NULL; } - num_arrays = wl_message_count_arrays(message); - closure = malloc(sizeof *closure + size + - num_arrays * sizeof(struct wl_array)); - if (closure == NULL) { - errno = ENOMEM; - wl_connection_consume(connection, size); - return NULL; - } + count = closure->count; array_extra = closure->extra; p = (uint32_t *)(closure->extra + num_arrays); @@ -785,9 +801,6 @@ wl_connection_demarshal(struct wl_connection *connection, } } - closure->count = count; - closure->message = message; - wl_connection_consume(connection, size); return closure; From 52609ddf79a96fee0465006e2c6339a3a5d23a87 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:19 -0600 Subject: [PATCH 0466/1152] connection: Clear fds we shouldn't close to -1 This initializes all the fd arguments in closures to -1 and clears them back to -1 when they've been dispatched or serialized. This means that any valid fd in a closure is currently libwayland's responsibility to close in the case of an error. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/connection.c b/src/connection.c index 8d8eb60c..29f565bb 100644 --- a/src/connection.c +++ b/src/connection.c @@ -524,6 +524,17 @@ wl_argument_from_va_list(const char *signature, union wl_argument *args, } } +static void +wl_closure_clear_fds(struct wl_closure *closure) +{ + int i; + + for (i = 0; closure->message->signature[i]; i++) { + if (closure->message->signature[i] == 'h') + closure->args[i].h = -1; + } +} + static struct wl_closure * wl_closure_init(const struct wl_message *message, uint32_t size, int *num_arrays, union wl_argument *args) @@ -557,6 +568,14 @@ wl_closure_init(const struct wl_message *message, uint32_t size, closure->message = message; closure->count = count; + /* Set these all to -1 so we can close any that have been + * set to a real value during wl_closure_destroy(). + * We may have copied a bunch of fds into the closure with + * memcpy previously, but those are undup()d client fds + * that we would have replaced anyway. + */ + wl_closure_clear_fds(closure); + return closure; } @@ -948,6 +967,8 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags, opcode, target->interface->name); } ffi_call(&cif, implementation[opcode], NULL, ffi_args); + + wl_closure_clear_fds(closure); } void @@ -956,6 +977,8 @@ wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher, { dispatcher(target->implementation, target, opcode, closure->message, closure->args); + + wl_closure_clear_fds(closure); } static int @@ -980,6 +1003,7 @@ copy_fds_to_connection(struct wl_closure *closure, "can't send file descriptor"); return -1; } + closure->args[i].h = -1; } return 0; From 46e4ea43a2ec546211f72be84b6a55188fb61626 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:20 -0600 Subject: [PATCH 0467/1152] connection: Make wl_closure_destroy() close fds of undispatched closures When we have a closure that can't be dispatched for some reason, and it contains file descriptors, we must close those descriptors to prevent leaking them. Previous commits ensure that only FDs belonging to this invocation of the closure, i.e. not FDs provided by the client for marshalling, nor FDs which have already been dispatched to either client or server, will be left in the closure by destroy time. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/connection.c b/src/connection.c index 29f565bb..e92de794 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1273,8 +1273,29 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send) fprintf(stderr, ")\n"); } +static int +wl_closure_close_fds(struct wl_closure *closure) +{ + int i; + struct argument_details arg; + const char *signature = closure->message->signature; + + for (i = 0; i < closure->count; i++) { + signature = get_next_argument(signature, &arg); + if (arg.type == 'h' && closure->args[i].h != -1) + close(closure->args[i].h); + } + + return 0; +} + void wl_closure_destroy(struct wl_closure *closure) { + /* wl_closure_destroy has free() semantics */ + if (!closure) + return; + + wl_closure_close_fds(closure); free(closure); } From b4cf9e7d5e811a74812eb682512b3ef51c79f4af Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:21 -0600 Subject: [PATCH 0468/1152] util: Pass flags to map iterators On the client side we're going to need to know if an object from the map is a zombie before we attempt to dereference it, so we need to pass this to the iterator. Reviewed-by: Daniel Stone Signed-off-by: Derek Foreman --- src/wayland-private.h | 3 ++- src/wayland-server.c | 11 +++++------ src/wayland-util.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index 434cb04e..93cec6be 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -80,7 +80,8 @@ struct wl_map { }; typedef enum wl_iterator_result (*wl_iterator_func_t)(void *element, - void *data); + void *data, + uint32_t flags); void wl_map_init(struct wl_map *map, uint32_t side); diff --git a/src/wayland-server.c b/src/wayland-server.c index 61e03150..cd5501f7 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -658,11 +658,9 @@ resource_is_deprecated(struct wl_resource *resource) } static enum wl_iterator_result -destroy_resource(void *element, void *data) +destroy_resource(void *element, void *data, uint32_t flags) { struct wl_resource *resource = element; - struct wl_client *client = resource->client; - uint32_t flags; wl_signal_emit(&resource->deprecated_destroy_signal, resource); /* Don't emit the new signal for deprecated resources, as that would @@ -670,7 +668,6 @@ destroy_resource(void *element, void *data) if (!resource_is_deprecated(resource)) wl_priv_signal_emit(&resource->destroy_signal, resource); - flags = wl_map_lookup_flags(&client->objects, resource->object.id); if (resource->destroy) resource->destroy(resource); @@ -685,9 +682,11 @@ wl_resource_destroy(struct wl_resource *resource) { struct wl_client *client = resource->client; uint32_t id; + uint32_t flags; id = resource->object.id; - destroy_resource(resource, NULL); + flags = wl_map_lookup_flags(&client->objects, id); + destroy_resource(resource, NULL, flags); if (id < WL_SERVER_ID_START) { if (client->display_resource) { @@ -1839,7 +1838,7 @@ struct wl_resource_iterator_context { }; static enum wl_iterator_result -resource_iterator_helper(void *res, void *user_data) +resource_iterator_helper(void *res, void *user_data, uint32_t flags) { struct wl_resource_iterator_context *context = user_data; struct wl_resource *resource = res; diff --git a/src/wayland-util.c b/src/wayland-util.c index cab7fc50..ce387f4b 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -371,7 +371,7 @@ for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) for (p = start; p < end; p++) if (p->data && !map_entry_is_free(*p)) { - ret = func(map_entry_get_data(*p), data); + ret = func(map_entry_get_data(*p), data, map_entry_get_flags(*p)); if (ret != WL_ITERATOR_CONTINUE) break; } From 69fab4fffcab68e355a5c181641cee5a4ead769f Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 28 Dec 2017 15:15:46 +0000 Subject: [PATCH 0469/1152] client: Add wl_object_is_zombie() helper function Add a helper function which determines whether or not an object is a zombie. [daniels: Extracted from Derek's bespoke-zombie patch as an intermediate step.] Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 10 +++++++++- src/wayland-client.c | 4 ++-- src/wayland-private.h | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/connection.c b/src/connection.c index e92de794..2e234ea5 100644 --- a/src/connection.c +++ b/src/connection.c @@ -831,6 +831,14 @@ wl_connection_demarshal(struct wl_connection *connection, return NULL; } +bool +wl_object_is_zombie(struct wl_map *map, uint32_t id) +{ + struct wl_object *object = wl_map_lookup(map, id); + + return (object == WL_ZOMBIE_OBJECT); +} + int wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) { @@ -852,7 +860,7 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) closure->args[i].o = NULL; object = wl_map_lookup(objects, id); - if (object == WL_ZOMBIE_OBJECT) { + if (wl_object_is_zombie(objects, id)) { /* references object we've already * destroyed client side */ object = NULL; diff --git a/src/wayland-client.c b/src/wayland-client.c index 795b4e9e..126dd908 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -837,7 +837,7 @@ display_handle_delete_id(void *data, struct wl_display *display, uint32_t id) if (!proxy) wl_log("error: received delete_id for unknown id (%u)\n", id); - if (proxy && proxy != WL_ZOMBIE_OBJECT) + if (proxy && !wl_object_is_zombie(&display->objects, id)) proxy->flags |= WL_PROXY_FLAG_ID_DELETED; else wl_map_remove(&display->objects, id); @@ -1253,7 +1253,7 @@ queue_event(struct wl_display *display, int len) return 0; proxy = wl_map_lookup(&display->objects, id); - if (!proxy || proxy == WL_ZOMBIE_OBJECT) { + if (!proxy || wl_object_is_zombie(&display->objects, id)) { wl_connection_consume(display->connection, size); return size; } diff --git a/src/wayland-private.h b/src/wayland-private.h index 93cec6be..c82b1f3e 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -190,6 +190,9 @@ wl_connection_demarshal(struct wl_connection *connection, struct wl_map *objects, const struct wl_message *message); +bool +wl_object_is_zombie(struct wl_map *map, uint32_t id); + int wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects); From 07d7a9968d9bf258794964584f68777686c90748 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 28 Dec 2017 15:22:25 +0000 Subject: [PATCH 0470/1152] client: Add WL_MAP_ENTRY_ZOMBIE flag Add a new map entry flag to indicate that the object received is valid, but a zombie. Previously this relied on a fixed object pointer, but future patches in this series will have map entries returning either NULL, or a different structure type entirely, for zombie objects. wl_object_is_zombie() now solely uses the new flag to determine whether or not the object is a zombie. [daniels: Extracted from Derek's bespoke-zombie patch as an intermediate step.] Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 13 +++++++++++-- src/wayland-client.c | 14 ++++++++------ src/wayland-private.h | 3 ++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/connection.c b/src/connection.c index 2e234ea5..426be574 100644 --- a/src/connection.c +++ b/src/connection.c @@ -834,9 +834,18 @@ wl_connection_demarshal(struct wl_connection *connection, bool wl_object_is_zombie(struct wl_map *map, uint32_t id) { - struct wl_object *object = wl_map_lookup(map, id); + uint32_t flags; - return (object == WL_ZOMBIE_OBJECT); + /* Zombie objects only exist on the client side. */ + if (map->side == WL_MAP_SERVER_SIDE) + return false; + + /* Zombie objects can only have been created by the client. */ + if (id >= WL_SERVER_ID_START) + return false; + + flags = wl_map_lookup_flags(map, id); + return !!(flags & WL_MAP_ENTRY_ZOMBIE); } int diff --git a/src/wayland-client.c b/src/wayland-client.c index 126dd908..8fc56340 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -405,15 +405,17 @@ wl_proxy_create_for_id(struct wl_proxy *factory, static void proxy_destroy(struct wl_proxy *proxy) { - if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) + if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) { wl_map_remove(&proxy->display->objects, proxy->object.id); - else if (proxy->object.id < WL_SERVER_ID_START) - wl_map_insert_at(&proxy->display->objects, 0, - proxy->object.id, WL_ZOMBIE_OBJECT); - else + } else if (proxy->object.id < WL_SERVER_ID_START) { + wl_map_insert_at(&proxy->display->objects, + WL_MAP_ENTRY_ZOMBIE, + proxy->object.id, + WL_ZOMBIE_OBJECT); + } else { wl_map_insert_at(&proxy->display->objects, 0, proxy->object.id, NULL); - + } proxy->flags |= WL_PROXY_FLAG_DESTROYED; diff --git a/src/wayland-private.h b/src/wayland-private.h index c82b1f3e..b0d129f7 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -69,7 +69,8 @@ wl_interface_equal(const struct wl_interface *iface1, * flags. If more flags are ever added, the implementation of wl_map will have * to change to allow for new flags */ enum wl_map_entry_flags { - WL_MAP_ENTRY_LEGACY = (1 << 0) + WL_MAP_ENTRY_LEGACY = (1 << 0), /* Server side only */ + WL_MAP_ENTRY_ZOMBIE = (1 << 0) /* Client side only */ }; struct wl_map { From 712ba320db29923197158905703cc81fa9b0b3e5 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 28 Dec 2017 15:28:11 +0000 Subject: [PATCH 0471/1152] client: Restructure delete_id handler control flow This makes it easier for future patches in the series, which can possibly return NULL for extant map entries. [daniels: Extracted from Derek's bespoke-zombie patch as an intermediate step.] Reviewed-by: Daniel Stone --- src/wayland-client.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 8fc56340..83f76ec2 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -836,13 +836,12 @@ display_handle_delete_id(void *data, struct wl_display *display, uint32_t id) proxy = wl_map_lookup(&display->objects, id); - if (!proxy) - wl_log("error: received delete_id for unknown id (%u)\n", id); - - if (proxy && !wl_object_is_zombie(&display->objects, id)) + if (wl_object_is_zombie(&display->objects, id)) + wl_map_remove(&display->objects, id); + else if (proxy) proxy->flags |= WL_PROXY_FLAG_ID_DELETED; else - wl_map_remove(&display->objects, id); + wl_log("error: received delete_id for unknown id (%u)\n", id); pthread_mutex_unlock(&display->mutex); } From c380adc554a3d0e2a567ff07deab020a3068304c Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 28 Dec 2017 15:30:09 +0000 Subject: [PATCH 0472/1152] client: Remove WL_ZOMBIE_OBJECT global Since we now have the WL_MAP_ENTRY_ZOMBIE flag to determine whether or not a client-side object is a zombie, we can remove the faux object. [daniels: Extracted from Derek's bespoke-zombie patch as an intermediate step.] Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/wayland-client.c | 2 +- src/wayland-private.h | 3 --- src/wayland-util.c | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 83f76ec2..21ef5b04 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -411,7 +411,7 @@ proxy_destroy(struct wl_proxy *proxy) wl_map_insert_at(&proxy->display->objects, WL_MAP_ENTRY_ZOMBIE, proxy->object.id, - WL_ZOMBIE_OBJECT); + NULL); } else { wl_map_insert_at(&proxy->display->objects, 0, proxy->object.id, NULL); diff --git a/src/wayland-private.h b/src/wayland-private.h index b0d129f7..8e94864a 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -57,9 +57,6 @@ struct wl_object { uint32_t id; }; -extern struct wl_object global_zombie_object; -#define WL_ZOMBIE_OBJECT ((void*)&global_zombie_object) - int wl_interface_equal(const struct wl_interface *iface1, const struct wl_interface *iface2); diff --git a/src/wayland-util.c b/src/wayland-util.c index ce387f4b..3a471a88 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -153,8 +153,6 @@ wl_array_copy(struct wl_array *array, struct wl_array *source) /** \cond */ -struct wl_object global_zombie_object; - int wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) { From b39d8933973394432bf994b0c6e564fdaceb4757 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 28 Dec 2017 15:41:18 +0000 Subject: [PATCH 0473/1152] client: Use refcount exclusively for destruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit e273c7cde added a refcount to wl_proxy. The refcount is set to 1 on creation, decreased when the client explicitly destroys the proxy, and is increased and decreased every time an event referencing that proxy is queued. Assuming no bugs, this means the refcount cannot reach 0 without the proxy being explicitly destroyed. However, some (not all) of the proxy-unref paths were only destroying the proxy if it had already been deleted. This should already be enforced by refcounting, so remove the check and rely solely on the refcount as the arbiter of when to free a proxy. Signed-off-by: Daniel Stone Reviewed-by: Derek Foreman Cc: Jonas Ådahl --- src/wayland-client.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 21ef5b04..55838cd9 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -258,7 +258,6 @@ wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; struct wl_proxy *proxy; - bool proxy_destroyed; while (!wl_list_empty(&queue->event_list)) { closure = container_of(queue->event_list.next, @@ -268,10 +267,8 @@ wl_event_queue_release(struct wl_event_queue *queue) decrease_closure_args_refcount(closure); proxy = closure->proxy; - proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); - proxy->refcount--; - if (proxy_destroyed && !proxy->refcount) + if (!proxy->refcount) free(proxy); wl_closure_destroy(closure); @@ -1310,10 +1307,10 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); proxy->refcount--; - if (proxy_destroyed) { - if (!proxy->refcount) - free(proxy); + if (!proxy->refcount) + free(proxy); + if (proxy_destroyed) { wl_closure_destroy(closure); return; } From 430c7820c31608dd29408fc800530b4fd08ff777 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 28 Dec 2017 15:50:06 +0000 Subject: [PATCH 0474/1152] client: Add wl_proxy_unref helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than open-coded decrement-and-maybe-free, introduce a wl_proxy_unref helper to do this for us. This will come in useful for future patches, where we may also have to free a zombie object. Signed-off-by: Daniel Stone Reviewed-by: Derek Foreman Cc: Jonas Ådahl --- src/wayland-client.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 55838cd9..f3d71b0e 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -222,6 +222,19 @@ wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) queue->display = display; } +static void +wl_proxy_unref(struct wl_proxy *proxy) +{ + assert(proxy->refcount > 0); + if (--proxy->refcount > 0) + return; + + /* If we get here, the client must have explicitly requested + * deletion. */ + assert(proxy->flags & WL_PROXY_FLAG_DESTROYED); + free(proxy); +} + static void decrease_closure_args_refcount(struct wl_closure *closure) { @@ -241,10 +254,7 @@ decrease_closure_args_refcount(struct wl_closure *closure) if (proxy) { if (proxy->flags & WL_PROXY_FLAG_DESTROYED) closure->args[i].o = NULL; - - proxy->refcount--; - if (!proxy->refcount) - free(proxy); + wl_proxy_unref(proxy); } break; default: @@ -257,20 +267,13 @@ static void wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; - struct wl_proxy *proxy; while (!wl_list_empty(&queue->event_list)) { closure = container_of(queue->event_list.next, struct wl_closure, link); wl_list_remove(&closure->link); - decrease_closure_args_refcount(closure); - - proxy = closure->proxy; - proxy->refcount--; - if (!proxy->refcount) - free(proxy); - + wl_proxy_unref(closure->proxy); wl_closure_destroy(closure); } } @@ -416,9 +419,7 @@ proxy_destroy(struct wl_proxy *proxy) proxy->flags |= WL_PROXY_FLAG_DESTROYED; - proxy->refcount--; - if (!proxy->refcount) - free(proxy); + wl_proxy_unref(proxy); } /** Destroy a proxy object @@ -1305,11 +1306,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) decrease_closure_args_refcount(closure); proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); - - proxy->refcount--; - if (!proxy->refcount) - free(proxy); - + wl_proxy_unref(proxy); if (proxy_destroyed) { wl_closure_destroy(closure); return; From 9744de9f472ec1e3c0e5b3416c097255e3bfdf12 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 28 Dec 2017 16:05:59 +0000 Subject: [PATCH 0475/1152] client: Plug a race in proxy destruction vs. dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closures created to hold events which will be dispatched on the client, take a reference to the proxy for the object the event was sent to, as well as the proxies for all objects referenced in that event. These references are dropped immediately before dispatch, with the display lock also being released. This leaves the potential for a vanishingly small race, where another thread drops the last reference on one of the proxies used in an event as it is being dispatched. Fix this by splitting decrease_closure_args_refcount into two functions: one which validates the objects (to ensure that clients are not returned objects which they have destroyed), and another which unrefs all proxies on the closure (object event was sent to, all referenced objects) as well as the closure itself. For symmetry, increase_closure_args_refcount is now the place where the refcount for the proxy for the object the event was sent to, is increased. This also happens to fix a bug: previously, if an event was sent to a client-destroyed object, and the event had object arguments, a reference would be leaked on the proxy for each of the object arguments. Found by inspection whilst reviewing the zombie-FD-leak series. Signed-off-by: Daniel Stone Reviewed-by: Derek Foreman Cc: Jonas Ådahl Cc: Pekka Paalanen --- src/wayland-client.c | 59 +++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index f3d71b0e..987418a1 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -236,7 +236,7 @@ wl_proxy_unref(struct wl_proxy *proxy) } static void -decrease_closure_args_refcount(struct wl_closure *closure) +validate_closure_objects(struct wl_closure *closure) { const char *signature; struct argument_details arg; @@ -251,11 +251,8 @@ decrease_closure_args_refcount(struct wl_closure *closure) case 'n': case 'o': proxy = (struct wl_proxy *) closure->args[i].o; - if (proxy) { - if (proxy->flags & WL_PROXY_FLAG_DESTROYED) - closure->args[i].o = NULL; - wl_proxy_unref(proxy); - } + if (proxy && proxy->flags & WL_PROXY_FLAG_DESTROYED) + closure->args[i].o = NULL; break; default: break; @@ -263,6 +260,37 @@ decrease_closure_args_refcount(struct wl_closure *closure) } } +/* Destroys a closure which was demarshaled for dispatch; unrefs all the + * proxies in its arguments, as well as its own proxy, and destroys the + * closure itself. */ +static void +destroy_queued_closure(struct wl_closure *closure) +{ + const char *signature; + struct argument_details arg; + struct wl_proxy *proxy; + int i, count; + + signature = closure->message->signature; + count = arg_count_for_signature(signature); + for (i = 0; i < count; i++) { + signature = get_next_argument(signature, &arg); + switch (arg.type) { + case 'n': + case 'o': + proxy = (struct wl_proxy *) closure->args[i].o; + if (proxy) + wl_proxy_unref(proxy); + break; + default: + break; + } + } + + wl_proxy_unref(closure->proxy); + wl_closure_destroy(closure); +} + static void wl_event_queue_release(struct wl_event_queue *queue) { @@ -272,9 +300,7 @@ wl_event_queue_release(struct wl_event_queue *queue) closure = container_of(queue->event_list.next, struct wl_closure, link); wl_list_remove(&closure->link); - decrease_closure_args_refcount(closure); - wl_proxy_unref(closure->proxy); - wl_closure_destroy(closure); + destroy_queued_closure(closure); } } @@ -1232,6 +1258,8 @@ increase_closure_args_refcount(struct wl_closure *closure) break; } } + + closure->proxy->refcount++; } static int @@ -1273,9 +1301,8 @@ queue_event(struct wl_display *display, int len) return -1; } - increase_closure_args_refcount(closure); - proxy->refcount++; closure->proxy = proxy; + increase_closure_args_refcount(closure); if (proxy == &display->proxy) queue = &display->display_queue; @@ -1302,13 +1329,11 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) /* Verify that the receiving object is still valid by checking if has * been destroyed by the application. */ - - decrease_closure_args_refcount(closure); + validate_closure_objects(closure); proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); - wl_proxy_unref(proxy); if (proxy_destroyed) { - wl_closure_destroy(closure); + destroy_queued_closure(closure); return; } @@ -1328,9 +1353,9 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) &proxy->object, opcode, proxy->user_data); } - wl_closure_destroy(closure); - pthread_mutex_lock(&display->mutex); + + destroy_queued_closure(closure); } static int From 4485ed1f59cb8695f3ab690e074abd7e79a27640 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:22 -0600 Subject: [PATCH 0476/1152] client: Replace the singleton zombie with bespoke zombies Using the singleton zombie object doesn't allow us to posthumously retain object interface information, which makes it difficult to properly inter future events destined for the recently deceased proxy. Notably, this makes it impossible for zombie proxy destined file descriptors to be properly consumed. When we create a proxy, we now create a zombie-state object to hold information about the file descriptors in events it can receive. This will allow us, in a future patch, to close those FDs. [daniels: Split Derek's patch into a few smaller ones.] Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/wayland-client.c | 82 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 987418a1..62d4f222 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -55,6 +55,11 @@ enum wl_proxy_flag { WL_PROXY_FLAG_WRAPPER = (1 << 2), }; +struct wl_zombie { + int event_count; + int *fd_count; +}; + struct wl_proxy { struct wl_object object; struct wl_display *display; @@ -350,6 +355,66 @@ wl_display_create_queue(struct wl_display *display) return queue; } +static int +message_count_fds(const char *signature) +{ + unsigned int count, i, fds = 0; + struct argument_details arg; + + count = arg_count_for_signature(signature); + for (i = 0; i < count; i++) { + signature = get_next_argument(signature, &arg); + if (arg.type == 'h') + fds++; + } + + return fds; +} + +static struct wl_zombie * +prepare_zombie(struct wl_proxy *proxy) +{ + const struct wl_interface *interface = proxy->object.interface; + const struct wl_message *message; + int i, count; + struct wl_zombie *zombie = NULL; + + /* If we hit an event with an FD, ensure we have a zombie object and + * fill the fd_count slot for that event with the number of FDs for + * that event. Interfaces with no events containing FDs will not have + * zombie objects created. */ + for (i = 0; i < interface->event_count; i++) { + message = &interface->events[i]; + count = message_count_fds(message->signature); + + if (!count) + continue; + + if (!zombie) { + zombie = zalloc(sizeof(*zombie) + + (interface->event_count * sizeof(int))); + if (!zombie) + return NULL; + + zombie->event_count = interface->event_count; + zombie->fd_count = (int *) &zombie[1]; + } + + zombie->fd_count[i] = count; + } + + return zombie; +} + +static enum wl_iterator_result +free_zombies(void *element, void *data, uint32_t flags) +{ + if (flags & WL_MAP_ENTRY_ZOMBIE) + free(element); + + return WL_ITERATOR_CONTINUE; +} + static struct wl_proxy * proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, uint32_t version) @@ -434,10 +499,14 @@ proxy_destroy(struct wl_proxy *proxy) if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) { wl_map_remove(&proxy->display->objects, proxy->object.id); } else if (proxy->object.id < WL_SERVER_ID_START) { + struct wl_zombie *zombie = prepare_zombie(proxy); + + /* The map now contains the zombie entry, until the delete_id + * event arrives. */ wl_map_insert_at(&proxy->display->objects, WL_MAP_ENTRY_ZOMBIE, proxy->object.id, - NULL); + zombie); } else { wl_map_insert_at(&proxy->display->objects, 0, proxy->object.id, NULL); @@ -860,12 +929,16 @@ display_handle_delete_id(void *data, struct wl_display *display, uint32_t id) proxy = wl_map_lookup(&display->objects, id); - if (wl_object_is_zombie(&display->objects, id)) + if (wl_object_is_zombie(&display->objects, id)) { + /* For zombie objects, the 'proxy' is actually the zombie + * event-information structure, which we can free. */ + free(proxy); wl_map_remove(&display->objects, id); - else if (proxy) + } else if (proxy) { proxy->flags |= WL_PROXY_FLAG_ID_DELETED; - else + } else { wl_log("error: received delete_id for unknown id (%u)\n", id); + } pthread_mutex_unlock(&display->mutex); } @@ -1087,6 +1160,7 @@ WL_EXPORT void wl_display_disconnect(struct wl_display *display) { wl_connection_destroy(display->connection); + wl_map_for_each(&display->objects, free_zombies, NULL); wl_map_release(&display->objects); wl_event_queue_release(&display->default_queue); wl_event_queue_release(&display->display_queue); From 239ba39331420f953de35c337ae57db35573f9cb Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:23 -0600 Subject: [PATCH 0477/1152] client: Consume file descriptors destined for zombie proxies We need to close file descriptors sent to zombie proxies to avoid leaking them, and perhaps more importantly, to prevent them from being dispatched in events on other objects (since they would previously be left in the buffer and potentially fed to following events destined for live proxies) Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/connection.c | 6 ++++++ src/wayland-client.c | 8 ++++++++ src/wayland-private.h | 3 +++ 3 files changed, 17 insertions(+) diff --git a/src/connection.c b/src/connection.c index 426be574..6f83bab2 100644 --- a/src/connection.c +++ b/src/connection.c @@ -192,6 +192,12 @@ close_fds(struct wl_buffer *buffer, int max) buffer->tail += size; } +void +wl_connection_close_fds_in(struct wl_connection *connection, int max) +{ + close_fds(&connection->fds_in, max); +} + int wl_connection_destroy(struct wl_connection *connection) { diff --git a/src/wayland-client.c b/src/wayland-client.c index 62d4f222..c1369b88 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1353,8 +1353,16 @@ queue_event(struct wl_display *display, int len) if (len < size) return 0; + /* If our proxy is gone or a zombie, just eat the event (and any FDs, + * if applicable). */ proxy = wl_map_lookup(&display->objects, id); if (!proxy || wl_object_is_zombie(&display->objects, id)) { + struct wl_zombie *zombie = wl_map_lookup(&display->objects, id); + + if (zombie) + wl_connection_close_fds_in(display->connection, + zombie->fd_count[opcode]); + wl_connection_consume(display->connection, size); return size; } diff --git a/src/wayland-private.h b/src/wayland-private.h index 8e94864a..12b9032c 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -253,4 +253,7 @@ wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify); void wl_priv_signal_emit(struct wl_priv_signal *signal, void *data); +void +wl_connection_close_fds_in(struct wl_connection *connection, int max); + #endif From f74c9b98db49ce16e037c3012590c4a24a4fc32e Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:24 -0600 Subject: [PATCH 0478/1152] tests: Add a test for fd leaks on zombie objects Until recently, if a client destroying a resource raced with the server generating an event on that resource that delivered a file descriptor, we would leak the fd. This tests for a leaked fd from that race condition. Reviewed-by: Daniel Stone Signed-off-by: Derek Foreman --- Makefile.am | 7 ++- protocol/tests.xml | 43 ++++++++++++++++++ tests/display-test.c | 102 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 protocol/tests.xml diff --git a/Makefile.am b/Makefile.am index 0eedb108..bceca2a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -114,7 +114,8 @@ protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml BUILT_SOURCES = \ $(nodist_libwayland_server_la_SOURCES) \ $(nodist_libwayland_client_la_SOURCES) \ - $(nodist_headers_test_SOURCES) + $(nodist_headers_test_SOURCES) \ + $(nodist_display_test_SOURCES) CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db DISTCLEANFILES = src/wayland-version.h @@ -206,6 +207,10 @@ client_test_SOURCES = tests/client-test.c client_test_LDADD = libtest-runner.la display_test_SOURCES = tests/display-test.c display_test_LDADD = libtest-runner.la +nodist_display_test_SOURCES = \ + protocol/tests-server-protocol.h \ + protocol/tests-client-protocol.h \ + protocol/tests-protocol.c connection_test_SOURCES = tests/connection-test.c connection_test_LDADD = libtest-runner.la event_loop_test_SOURCES = tests/event-loop-test.c diff --git a/protocol/tests.xml b/protocol/tests.xml new file mode 100644 index 00000000..77f6e243 --- /dev/null +++ b/protocol/tests.xml @@ -0,0 +1,43 @@ + + + + + Copyright © 2017 Samsung Electronics Co., Ltd + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + + + + A trivial interface for fd passing tests. + + + + + + + + + + + + diff --git a/tests/display-test.c b/tests/display-test.c index e6f03693..06231585 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -47,6 +47,9 @@ #include "test-runner.h" #include "test-compositor.h" +#include "tests-server-protocol.h" +#include "tests-client-protocol.h" + struct display_destroy_listener { struct wl_listener listener; int done; @@ -1066,3 +1069,102 @@ TEST(bind_fails_on_filtered_global) display_destroy(d); } + +static void +pre_fd(void *data, struct fd_passer *fdp) +{ + fd_passer_destroy(fdp); +} + +static void +fd(void *data, struct fd_passer *fdp, int32_t fd) +{ + /* We destroyed the resource before this event */ + assert(false); +} + +struct fd_passer_listener fd_passer_listener = { + pre_fd, + fd, +}; + +static void +zombie_fd_handle_globals(void *data, struct wl_registry *registry, + uint32_t id, const char *intf, uint32_t ver) +{ + struct fd_passer *fdp; + + if (!strcmp(intf, "fd_passer")) { + fdp = wl_registry_bind(registry, id, &fd_passer_interface, 1); + fd_passer_add_listener(fdp, &fd_passer_listener, NULL); + } +} + +static const struct wl_registry_listener zombie_fd_registry_listener = { + zombie_fd_handle_globals, + NULL +}; + +static void +zombie_client(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, &zombie_fd_registry_listener, NULL); + + /* Gets the registry */ + wl_display_roundtrip(c->wl_display); + + /* push out the fd_passer bind */ + wl_display_roundtrip(c->wl_display); + + /* push out our fd_passer.destroy */ + wl_display_roundtrip(c->wl_display); + + wl_registry_destroy(registry); + + client_disconnect_nocheck(c); +} + +static void +fd_passer_clobber(struct wl_client *client, struct wl_resource *res) +{ + wl_resource_destroy(res); +} + +static const struct fd_passer_interface fdp_interface = { + fd_passer_clobber, +}; + +static void +bind_fd_passer(struct wl_client *client, void *data, + uint32_t vers, uint32_t id) +{ + struct wl_resource *res; + + res = wl_resource_create(client, &fd_passer_interface, vers, id); + wl_resource_set_implementation(res, &fdp_interface, NULL, NULL); + assert(res); + fd_passer_send_pre_fd(res); + fd_passer_send_fd(res, fileno(stdin)); +} + +TEST(zombie_fd) +{ + struct display *d; + struct wl_global *g; + + d = display_create(); + + g = wl_global_create(d->wl_display, &fd_passer_interface, + 1, d, bind_fd_passer); + + client_create_noarg(d, zombie_client); + display_run(d); + + wl_global_destroy(g); + + display_destroy(d); +} From ff992951a7e6da0a8e54786ef7371ae420ce6c9c Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 6 Dec 2017 11:22:25 -0600 Subject: [PATCH 0479/1152] tests: Check for wrong fd delivery with zombie objects Until recently, if an event attempting to deliver an fd to a zombie object was demarshalled after the object was made into a zombie, we leaked the fd and left it in the buffer. If another event attempting to deliver an fd to a live object was in that same buffer, the zombie's fd would be delivered instead. This test recreates that situation. While this is a ridiculously contrived way to force this race - delivering an event from a destruction handler - I do have reports of this race being hit in real world code. Signed-off-by: Derek Foreman Acked-by: Daniel Stone --- protocol/tests.xml | 11 +++- tests/display-test.c | 153 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 4 deletions(-) diff --git a/protocol/tests.xml b/protocol/tests.xml index 77f6e243..ea56ae49 100644 --- a/protocol/tests.xml +++ b/protocol/tests.xml @@ -26,7 +26,7 @@ SOFTWARE. - + A trivial interface for fd passing tests. @@ -39,5 +39,14 @@ + + + + + Tells this fd passer object about another one to send events + to for more complicated fd leak tests. + + + diff --git a/tests/display-test.c b/tests/display-test.c index 06231585..9b49a0ec 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1128,27 +1128,83 @@ zombie_client(void *data) client_disconnect_nocheck(c); } +struct passer_data { + struct wl_resource *conjoined_passer; +}; + +static void +feed_pipe(int fd, char tosend) +{ + int count; + + do { + count = write(fd, &tosend, 1); + } while (count != 1 && errno == EAGAIN); + assert(count == 1); + close(fd); +} + static void fd_passer_clobber(struct wl_client *client, struct wl_resource *res) { + struct passer_data *pdata = wl_resource_get_user_data(res); + int pipes1[2], pipes2[2], ret; + + if (pdata->conjoined_passer) { + ret = pipe(pipes1); + assert(ret == 0); + ret = pipe(pipes2); + assert(ret == 0); + + wl_resource_queue_event(res, FD_PASSER_FD, pipes1[0]); + fd_passer_send_fd(pdata->conjoined_passer, pipes2[0]); + feed_pipe(pipes1[1], '1'); + feed_pipe(pipes2[1], '2'); + close(pipes1[0]); + close(pipes2[0]); + } wl_resource_destroy(res); } +static void +fd_passer_twin(struct wl_client *client, struct wl_resource *res, struct wl_resource *passer) +{ + struct passer_data *pdata = wl_resource_get_user_data(res); + + pdata->conjoined_passer = passer; +} + static const struct fd_passer_interface fdp_interface = { fd_passer_clobber, + fd_passer_twin }; +static void +pdata_destroy(struct wl_resource *res) +{ + struct passer_data *pdata = wl_resource_get_user_data(res); + + free(pdata); +} + static void bind_fd_passer(struct wl_client *client, void *data, uint32_t vers, uint32_t id) { struct wl_resource *res; + struct passer_data *pdata; + + pdata = malloc(sizeof(*pdata)); + assert(pdata); + pdata->conjoined_passer = NULL; res = wl_resource_create(client, &fd_passer_interface, vers, id); - wl_resource_set_implementation(res, &fdp_interface, NULL, NULL); + wl_resource_set_implementation(res, &fdp_interface, pdata, pdata_destroy); assert(res); - fd_passer_send_pre_fd(res); - fd_passer_send_fd(res, fileno(stdin)); + if (vers == 1) { + fd_passer_send_pre_fd(res); + fd_passer_send_fd(res, fileno(stdin)); + } } TEST(zombie_fd) @@ -1168,3 +1224,94 @@ TEST(zombie_fd) display_destroy(d); } + + +static void +double_pre_fd(void *data, struct fd_passer *fdp) +{ + assert(false); +} + +static void +double_fd(void *data, struct fd_passer *fdp, int32_t fd) +{ + char buf; + int count; + + do { + count = read(fd, &buf, 1); + } while (count != 1 && errno == EAGAIN); + assert(count == 1); + + close(fd); + fd_passer_destroy(fdp); + assert(buf == '2'); +} + +struct fd_passer_listener double_fd_passer_listener = { + double_pre_fd, + double_fd, +}; + + +static void +double_zombie_fd_handle_globals(void *data, struct wl_registry *registry, + uint32_t id, const char *intf, uint32_t ver) +{ + struct fd_passer *fdp1, *fdp2; + + if (!strcmp(intf, "fd_passer")) { + fdp1 = wl_registry_bind(registry, id, &fd_passer_interface, 2); + fd_passer_add_listener(fdp1, &double_fd_passer_listener, NULL); + fdp2 = wl_registry_bind(registry, id, &fd_passer_interface, 2); + fd_passer_add_listener(fdp2, &double_fd_passer_listener, NULL); + fd_passer_conjoin(fdp1, fdp2); + fd_passer_destroy(fdp1); + } +} + +static const struct wl_registry_listener double_zombie_fd_registry_listener = { + double_zombie_fd_handle_globals, + NULL +}; + +static void +double_zombie_client(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, &double_zombie_fd_registry_listener, NULL); + + /* Gets the registry */ + wl_display_roundtrip(c->wl_display); + + /* One more so server can respond to conjoin+destroy */ + wl_display_roundtrip(c->wl_display); + + /* And finally push out our last fd_passer.destroy */ + wl_display_roundtrip(c->wl_display); + + wl_registry_destroy(registry); + + client_disconnect_nocheck(c); +} + +TEST(zombie_fd_errant_consumption) +{ + struct display *d; + struct wl_global *g; + + d = display_create(); + + g = wl_global_create(d->wl_display, &fd_passer_interface, + 2, d, bind_fd_passer); + + client_create_noarg(d, double_zombie_client); + display_run(d); + + wl_global_destroy(g); + + display_destroy(d); +} From 35ab47567cca5bafe80e193b9c6f134c78ef3871 Mon Sep 17 00:00:00 2001 From: "Fiedler, Mathias" Date: Tue, 5 Dec 2017 09:49:52 +0100 Subject: [PATCH 0480/1152] server: add log message when client connection is destroyed due to an error The client connection is destroyed by the server in several circumstances. This patch adds log messages in case the connection is destroyed due to an error other than normal hangup. Signed-off-by: Mathias Fiedler Reviewed-by: Derek Foreman --- src/wayland-server.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index cd5501f7..7225b4e9 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -300,6 +300,13 @@ wl_resource_post_error(struct wl_resource *resource, client->error = 1; } +static void +destroy_client_with_error(struct wl_client *client, const char *reason) +{ + wl_log("%s (pid %u)\n", reason, client->ucred.pid); + wl_client_destroy(client); +} + static int wl_client_connection_data(int fd, uint32_t mask, void *data) { @@ -314,15 +321,21 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) int opcode, size, since; int len; - if (mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP)) { + if (mask & WL_EVENT_HANGUP) { wl_client_destroy(client); return 1; } + if (mask & WL_EVENT_ERROR) { + destroy_client_with_error(client, "socket error"); + return 1; + } + if (mask & WL_EVENT_WRITABLE) { len = wl_connection_flush(connection); if (len < 0 && errno != EAGAIN) { - wl_client_destroy(client); + destroy_client_with_error( + client, "failed to flush client connection"); return 1; } else if (len >= 0) { wl_event_source_fd_update(client->source, @@ -334,7 +347,8 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) if (mask & WL_EVENT_READABLE) { len = wl_connection_read(connection); if (len == 0 || (len < 0 && errno != EAGAIN)) { - wl_client_destroy(client); + destroy_client_with_error( + client, "failed to read client connection"); return 1; } } @@ -418,8 +432,10 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) len = wl_connection_pending_input(connection); } - if (client->error) - wl_client_destroy(client); + if (client->error) { + destroy_client_with_error(client, + "error in client communication"); + } return 1; } From 118aaec480a1153cccc81a38a69c1b6571d98b36 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 19 Jan 2018 11:51:35 -0600 Subject: [PATCH 0481/1152] tests: Add missing file to distribution In f74c9b98db49ce16e037c3012590c4a24a4fc32e I added tests.xml to the repository, but not to the distribution tarball. Signed-off-by: Derek Foreman Reviewed-by: Quentin Glidic Reviewed-by: Daniel Stone --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index bceca2a8..1d21fa2b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -264,6 +264,7 @@ exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la EXTRA_DIST = tests/scanner-test.sh \ + protocol/tests.xml \ tests/data/example.xml \ tests/data/example-client.h \ tests/data/example-server.h \ From e5b52f673c508a5f95c88c6cc99026cd2b762b5e Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 19 Jan 2018 15:20:31 -0600 Subject: [PATCH 0482/1152] connection: Clear correct args when clearing fds to -1 commit 52609ddf79a96fee0465006e2c6339a3a5d23a87 was intended to set fds to -1 in the arg list, however it failed to account for version information at the start of signatures. Most noticably, this broke mesa's create_prime_buffer by setting width to -1 instead of the fd, as the width was the argument following the fd, and the version was one byte long. This should close https://bugs.kde.org/show_bug.cgi?id=389200 Signed-off-by: Derek Foreman Reviewed-by: Pekka Paalanen Reviewed-by: Daniel Stone --- src/connection.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index 6f83bab2..5d5711f2 100644 --- a/src/connection.c +++ b/src/connection.c @@ -533,10 +533,13 @@ wl_argument_from_va_list(const char *signature, union wl_argument *args, static void wl_closure_clear_fds(struct wl_closure *closure) { + const char *signature = closure->message->signature; + struct argument_details arg; int i; - for (i = 0; closure->message->signature[i]; i++) { - if (closure->message->signature[i] == 'h') + for (i = 0; i < closure->count; i++) { + signature = get_next_argument(signature, &arg); + if (arg.type == 'h') closure->args[i].h = -1; } } From ef48ff21f0468c428127d131b27cbddc627a83a6 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Wed, 24 Jan 2018 14:28:15 +0100 Subject: [PATCH 0483/1152] doc: Document behavior of non-nullable object arguments in clients Reviewed-by: Pekka Paalanen --- src/wayland-util.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index caeac826..b6cbe0ea 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -78,12 +78,23 @@ extern "C" { * wl_message is to a protocol message like a class is to an object. * * The `name` of a wl_message is the name of the corresponding protocol message. + * * The `signature` is an ordered list of symbols representing the data types * of message arguments and, optionally, a protocol version and indicators for * nullability. A leading integer in the `signature` indicates the _since_ * version of the protocol message. A `?` preceding a data type symbol indicates - * that the following argument type is nullable. When no arguments accompany a - * message, `signature` is an empty string. + * that the following argument type is nullable. While it is a protocol violation + * to send messages with non-nullable arguments set to `NULL`, event handlers in + * clients might still get called with non-nullable object arguments set to + * `NULL`. This can happen when the client destroyed the object being used as + * argument on its side and an event referencing that object was sent before the + * server knew about its destruction. As this race cannot be prevented, clients + * should - as a general rule - program their event handlers such that they can + * handle object arguments declared non-nullable being `NULL` gracefully. + * + * When no arguments accompany a message, `signature` is an empty string. + * + * Symbols: * * * `i`: int * * `u`: uint From bf7cc6805396af8df3b40e10c63de701346c93dd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 13 Dec 2017 11:51:19 +0100 Subject: [PATCH 0484/1152] server: add wl_display_destroy_clients() Bug [1] reported that wl_display_destroy() doesn't destroy clients, so client socket file descriptors are being kept open until the compositor process exits. Patch [2] proposed to destroy clients in wl_display_destroy(). The patch was not accepted because doing so changes the ABI. Thus, a new wl_display_destroy_clients() function is added in this patch. It should be called by compositors right before wl_display_destroy(). [1] https://bugs.freedesktop.org/show_bug.cgi?id=99142 [2] https://patchwork.freedesktop.org/patch/128832/ Signed-off-by: Simon Ser Reviewed-by: Pekka Paalanen Acked-by: Daniel Stone --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index fd458c56..2e725d92 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -214,6 +214,9 @@ wl_display_run(struct wl_display *display); void wl_display_flush_clients(struct wl_display *display); +void +wl_display_destroy_clients(struct wl_display *display); + struct wl_client; typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, diff --git a/src/wayland-server.c b/src/wayland-server.c index 7225b4e9..eb1e5000 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1279,6 +1279,44 @@ wl_display_flush_clients(struct wl_display *display) } } +/** Destroy all clients connected to the display + * + * \param display The display object + * + * This function should be called right before wl_display_destroy() to ensure + * all client resources are closed properly. Destroying a client from within + * wl_display_destroy_clients() is safe, but creating one will leak resources + * and raise a warning. + * + * \memberof wl_display + */ +WL_EXPORT void +wl_display_destroy_clients(struct wl_display *display) +{ + struct wl_list tmp_client_list, *pos; + struct wl_client *client; + + /* Move the whole client list to a temporary head because some new clients + * might be added to the original head. */ + wl_list_init(&tmp_client_list); + wl_list_insert_list(&tmp_client_list, &display->client_list); + wl_list_init(&display->client_list); + + /* wl_list_for_each_safe isn't enough here: it fails if the next client is + * destroyed by the destroy handler of the current one. */ + while (!wl_list_empty(&tmp_client_list)) { + pos = tmp_client_list.next; + client = wl_container_of(pos, client, link); + + wl_client_destroy(client); + } + + if (!wl_list_empty(&display->client_list)) { + wl_log("wl_display_destroy_clients: cannot destroy all clients because " + "new ones were created by destroy callbacks\n"); + } +} + static int socket_data(int fd, uint32_t mask, void *data) { From 0fa3474be36be5fee98bebb169df68dcf806e3f3 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Mon, 5 Feb 2018 15:39:43 +0100 Subject: [PATCH 0485/1152] shm: provide actual error on mmap failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an mmap() fails, a WL_SHM_ERROR_INVALID_FD is raised and the client is killed. However, there is no indication of the actual system error that caused mmap() to fail, which makes such error harder to investigate. Provide the actual error message that caused mmap() to fail. Signed-off-by: Olivier Fourdan Reviewed-by: Jonas Ådahl --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 8e2ef77d..4191231d 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -281,7 +281,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, if (pool->data == MAP_FAILED) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, - "failed mmap fd %d", fd); + "failed mmap fd %d: %m", fd); goto err_free; } close(fd); From 549a5ea710f4da1a5749587176d39fef1ded4077 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:43 +0100 Subject: [PATCH 0486/1152] wayland-egl: import libwayland-egl.so frontend library from Mesa Currently the client-facing libwayland-egl API is defined by a header file shipped by Wayland, but the implementation is left to each vendor. This can cause collisions when multiple implementations are installed on the same system. Importing the implementation into Wayland with a stable and versioned driver-facing ABI allows multiple drivers to coexist on the same system. Pull the sample implementation from Mesa commit 677edff5cfd ("wayland-egl: rework and simplify wl_egl_window initialization") It has been used by the Mesa open source drivers, NVIDIA and others[1]. v2: Reword commit message, rebase on top of newer Mesa. [1] https://github.com/thayama/wayland-egl Cc: Miguel A. Vico Cc: James Jones Cc: Daniel Stone Cc: duncan-roe Cc: Takanari Hayama Suggested-by: Daniel Stone Signed-off-by: Emil Velikov Reviewed-by: Miguel A Vico Moya Reviewed-by: Arnaud Vrac --- egl/wayland-egl-abi-check.c | 235 ++++++++++++++++++++++++++++++++++ egl/wayland-egl-backend.h | 63 +++++++++ egl/wayland-egl-symbols-check | 16 +++ egl/wayland-egl.c | 109 ++++++++++++++++ egl/wayland-egl.pc.in | 11 ++ 5 files changed, 434 insertions(+) create mode 100644 egl/wayland-egl-abi-check.c create mode 100644 egl/wayland-egl-backend.h create mode 100755 egl/wayland-egl-symbols-check create mode 100644 egl/wayland-egl.c create mode 100644 egl/wayland-egl.pc.in diff --git a/egl/wayland-egl-abi-check.c b/egl/wayland-egl-abi-check.c new file mode 100644 index 00000000..62c51a22 --- /dev/null +++ b/egl/wayland-egl-abi-check.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include /* offsetof */ +#include /* printf */ + +#include "wayland-egl-backend.h" /* Current struct wl_egl_window implementation */ + +/* + * Following are previous implementations of wl_egl_window. + * + * DO NOT EVER CHANGE! + */ + +/* From: 214fc6e850 - Benjamin Franzke : egl: Implement libwayland-egl */ +struct wl_egl_window_v0 { + struct wl_surface *surface; + + int width; + int height; + int dx; + int dy; + + int attached_width; + int attached_height; +}; + +/* From: ca3ed3e024 - Ander Conselvan de Oliveira : egl/wayland: Don't invalidate drawable on swap buffers */ +struct wl_egl_window_v1 { + struct wl_surface *surface; + + int width; + int height; + int dx; + int dy; + + int attached_width; + int attached_height; + + void *private; + void (*resize_callback)(struct wl_egl_window *, void *); +}; + +/* From: 690ead4a13 - Stencel, Joanna : egl/wayland-egl: Fix for segfault in dri2_wl_destroy_surface. */ +#define WL_EGL_WINDOW_VERSION_v2 2 +struct wl_egl_window_v2 { + struct wl_surface *surface; + + int width; + int height; + int dx; + int dy; + + int attached_width; + int attached_height; + + void *private; + void (*resize_callback)(struct wl_egl_window *, void *); + void (*destroy_window_callback)(void *); +}; + +/* From: 2d5d61bc49 - Miguel A. Vico : wayland-egl: Make wl_egl_window a versioned struct */ +#define WL_EGL_WINDOW_VERSION_v3 3 +struct wl_egl_window_v3 { + const intptr_t version; + + int width; + int height; + int dx; + int dy; + + int attached_width; + int attached_height; + + void *private; + void (*resize_callback)(struct wl_egl_window *, void *); + void (*destroy_window_callback)(void *); + + struct wl_surface *surface; +}; + + +/* This program checks we keep a backwards-compatible struct wl_egl_window + * definition whenever it is modified in wayland-egl-backend.h. + * + * The previous definition should be added above as a new struct + * wl_egl_window_vN, and the appropriate checks should be added below + */ + +#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member) + +#define CHECK_RENAMED_MEMBER(a_ver, b_ver, a_member, b_member) \ + do { \ + if (offsetof(struct wl_egl_window ## a_ver, a_member) != \ + offsetof(struct wl_egl_window ## b_ver, b_member)) { \ + printf("Backards incompatible change detected!\n " \ + "offsetof(struct wl_egl_window" #a_ver "::" #a_member ") != " \ + "offsetof(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \ + return 1; \ + } \ + \ + if (MEMBER_SIZE(struct wl_egl_window ## a_ver, a_member) != \ + MEMBER_SIZE(struct wl_egl_window ## b_ver, b_member)) { \ + printf("Backards incompatible change detected!\n " \ + "MEMBER_SIZE(struct wl_egl_window" #a_ver "::" #a_member ") != " \ + "MEMBER_SIZE(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \ + return 1; \ + } \ + } while (0) + +#define CHECK_MEMBER(a_ver, b_ver, member) CHECK_RENAMED_MEMBER(a_ver, b_ver, member, member) +#define CHECK_MEMBER_CURRENT(a_ver, member) CHECK_MEMBER(a_ver,, member) + +#define CHECK_SIZE(a_ver, b_ver) \ + do { \ + if (sizeof(struct wl_egl_window ## a_ver) > \ + sizeof(struct wl_egl_window ## b_ver)) { \ + printf("Backards incompatible change detected!\n " \ + "sizeof(struct wl_egl_window" #a_ver ") > " \ + "sizeof(struct wl_egl_window" #b_ver ")\n"); \ + return 1; \ + } \ + } while (0) + +#define CHECK_SIZE_CURRENT(a_ver) \ + do { \ + if (sizeof(struct wl_egl_window ## a_ver) != \ + sizeof(struct wl_egl_window)) { \ + printf("Backards incompatible change detected!\n " \ + "sizeof(struct wl_egl_window" #a_ver ") != " \ + "sizeof(struct wl_egl_window)\n"); \ + return 1; \ + } \ + } while (0) + +#define CHECK_VERSION(a_ver, b_ver) \ + do { \ + if ((WL_EGL_WINDOW_VERSION ## a_ver) >= \ + (WL_EGL_WINDOW_VERSION ## b_ver)) { \ + printf("Backards incompatible change detected!\n " \ + "WL_EGL_WINDOW_VERSION" #a_ver " >= " \ + "WL_EGL_WINDOW_VERSION" #b_ver "\n"); \ + return 1; \ + } \ + } while (0) + +#define CHECK_VERSION_CURRENT(a_ver) \ + do { \ + if ((WL_EGL_WINDOW_VERSION ## a_ver) != \ + (WL_EGL_WINDOW_VERSION)) { \ + printf("Backards incompatible change detected!\n " \ + "WL_EGL_WINDOW_VERSION" #a_ver " != " \ + "WL_EGL_WINDOW_VERSION\n"); \ + return 1; \ + } \ + } while (0) + +int main(int argc, char **argv) +{ + /* Check wl_egl_window_v1 ABI against wl_egl_window_v0 */ + CHECK_MEMBER(_v0, _v1, surface); + CHECK_MEMBER(_v0, _v1, width); + CHECK_MEMBER(_v0, _v1, height); + CHECK_MEMBER(_v0, _v1, dx); + CHECK_MEMBER(_v0, _v1, dy); + CHECK_MEMBER(_v0, _v1, attached_width); + CHECK_MEMBER(_v0, _v1, attached_height); + + CHECK_SIZE(_v0, _v1); + + /* Check wl_egl_window_v2 ABI against wl_egl_window_v1 */ + CHECK_MEMBER(_v1, _v2, surface); + CHECK_MEMBER(_v1, _v2, width); + CHECK_MEMBER(_v1, _v2, height); + CHECK_MEMBER(_v1, _v2, dx); + CHECK_MEMBER(_v1, _v2, dy); + CHECK_MEMBER(_v1, _v2, attached_width); + CHECK_MEMBER(_v1, _v2, attached_height); + CHECK_MEMBER(_v1, _v2, private); + CHECK_MEMBER(_v1, _v2, resize_callback); + + CHECK_SIZE(_v1, _v2); + + /* Check wl_egl_window_v3 ABI against wl_egl_window_v2 */ + CHECK_RENAMED_MEMBER(_v2, _v3, surface, version); + CHECK_MEMBER (_v2, _v3, width); + CHECK_MEMBER (_v2, _v3, height); + CHECK_MEMBER (_v2, _v3, dx); + CHECK_MEMBER (_v2, _v3, dy); + CHECK_MEMBER (_v2, _v3, attached_width); + CHECK_MEMBER (_v2, _v3, attached_height); + CHECK_MEMBER (_v2, _v3, private); + CHECK_MEMBER (_v2, _v3, resize_callback); + CHECK_MEMBER (_v2, _v3, destroy_window_callback); + + CHECK_SIZE (_v2, _v3); + CHECK_VERSION(_v2, _v3); + + /* Check current wl_egl_window ABI against wl_egl_window_v3 */ + CHECK_MEMBER_CURRENT(_v3, version); + CHECK_MEMBER_CURRENT(_v3, width); + CHECK_MEMBER_CURRENT(_v3, height); + CHECK_MEMBER_CURRENT(_v3, dx); + CHECK_MEMBER_CURRENT(_v3, dy); + CHECK_MEMBER_CURRENT(_v3, attached_width); + CHECK_MEMBER_CURRENT(_v3, attached_height); + CHECK_MEMBER_CURRENT(_v3, private); + CHECK_MEMBER_CURRENT(_v3, resize_callback); + CHECK_MEMBER_CURRENT(_v3, destroy_window_callback); + CHECK_MEMBER_CURRENT(_v3, surface); + + CHECK_SIZE_CURRENT (_v3); + CHECK_VERSION_CURRENT(_v3); + + return 0; +} diff --git a/egl/wayland-egl-backend.h b/egl/wayland-egl-backend.h new file mode 100644 index 00000000..82f025cb --- /dev/null +++ b/egl/wayland-egl-backend.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Benjamin Franzke + */ + +#ifndef _WAYLAND_EGL_PRIV_H +#define _WAYLAND_EGL_PRIV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WL_EGL_WINDOW_VERSION 3 + +struct wl_surface; + +struct wl_egl_window { + const intptr_t version; + + int width; + int height; + int dx; + int dy; + + int attached_width; + int attached_height; + + void *private; + void (*resize_callback)(struct wl_egl_window *, void *); + void (*destroy_window_callback)(void *); + + struct wl_surface *surface; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check new file mode 100755 index 00000000..e7105ea5 --- /dev/null +++ b/egl/wayland-egl-symbols-check @@ -0,0 +1,16 @@ +#!/bin/sh + +FUNCS=$(nm -D --defined-only ${1-.libs/libwayland-egl.so} | grep -o "T .*" | cut -c 3- | while read func; do +( grep -q "^$func$" || echo $func ) < + * Benjamin Franzke + */ + +#include +#include + +#include "wayland-egl.h" +#include "wayland-egl-backend.h" + +/* GCC visibility */ +#if defined(__GNUC__) +#define WL_EGL_EXPORT __attribute__ ((visibility("default"))) +#else +#define WL_EGL_EXPORT +#endif + +WL_EGL_EXPORT void +wl_egl_window_resize(struct wl_egl_window *egl_window, + int width, int height, + int dx, int dy) +{ + if (width <= 0 || height <= 0) + return; + + egl_window->width = width; + egl_window->height = height; + egl_window->dx = dx; + egl_window->dy = dy; + + if (egl_window->resize_callback) + egl_window->resize_callback(egl_window, egl_window->private); +} + +WL_EGL_EXPORT struct wl_egl_window * +wl_egl_window_create(struct wl_surface *surface, + int width, int height) +{ + struct wl_egl_window *egl_window; + + if (width <= 0 || height <= 0) + return NULL; + + egl_window = calloc(1, sizeof *egl_window); + if (!egl_window) + return NULL; + + /* Cast away the constness to set the version number. + * + * We want the const notation since it gives an explicit + * feedback to the backend implementation, should it try to + * change it. + * + * The latter in itself is not too surprising as these days APIs + * tend to provide bidirectional version field. + */ + intptr_t *version = (intptr_t *)&egl_window->version; + *version = WL_EGL_WINDOW_VERSION; + + egl_window->surface = surface; + + egl_window->width = width; + egl_window->height = height; + + return egl_window; +} + +WL_EGL_EXPORT void +wl_egl_window_destroy(struct wl_egl_window *egl_window) +{ + if (egl_window->destroy_window_callback) + egl_window->destroy_window_callback(egl_window->private); + free(egl_window); +} + +WL_EGL_EXPORT void +wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, + int *width, int *height) +{ + if (width) + *width = egl_window->attached_width; + if (height) + *height = egl_window->attached_height; +} diff --git a/egl/wayland-egl.pc.in b/egl/wayland-egl.pc.in new file mode 100644 index 00000000..8a40cfac --- /dev/null +++ b/egl/wayland-egl.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: wayland-egl +Description: Mesa wayland-egl library +Version: @VERSION@ +Requires: wayland-client +Libs: -L${libdir} -lwayland-egl +Cflags: -I${includedir} From d71e4ca501c54889c81526eba46fafa8f26d89a9 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:44 +0100 Subject: [PATCH 0487/1152] wayland-egl: reuse the existing WL_EXPORT macro There's little point if redefining new one ourselves. Just reuse the one that's already available. Cc: Daniel Stone Suggested-by: Daniel Stone Signed-off-by: Emil Velikov Reviewed-by: Arnaud Vrac --- egl/wayland-egl.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/egl/wayland-egl.c b/egl/wayland-egl.c index e7cea895..02ac04e8 100644 --- a/egl/wayland-egl.c +++ b/egl/wayland-egl.c @@ -32,15 +32,10 @@ #include "wayland-egl.h" #include "wayland-egl-backend.h" +#include "wayland-util.h" -/* GCC visibility */ -#if defined(__GNUC__) -#define WL_EGL_EXPORT __attribute__ ((visibility("default"))) -#else -#define WL_EGL_EXPORT -#endif -WL_EGL_EXPORT void +WL_EXPORT void wl_egl_window_resize(struct wl_egl_window *egl_window, int width, int height, int dx, int dy) @@ -57,7 +52,7 @@ wl_egl_window_resize(struct wl_egl_window *egl_window, egl_window->resize_callback(egl_window, egl_window->private); } -WL_EGL_EXPORT struct wl_egl_window * +WL_EXPORT struct wl_egl_window * wl_egl_window_create(struct wl_surface *surface, int width, int height) { @@ -90,7 +85,7 @@ wl_egl_window_create(struct wl_surface *surface, return egl_window; } -WL_EGL_EXPORT void +WL_EXPORT void wl_egl_window_destroy(struct wl_egl_window *egl_window) { if (egl_window->destroy_window_callback) @@ -98,7 +93,7 @@ wl_egl_window_destroy(struct wl_egl_window *egl_window) free(egl_window); } -WL_EGL_EXPORT void +WL_EXPORT void wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, int *width, int *height) { From 6c7f96e8fea04ae81296b6188fb1aca6cd0391aa Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:45 +0100 Subject: [PATCH 0488/1152] wayland-egl: correct wayland-egl.pc description/version Drop the "Mesa" part from the commit message and change the version to 17.4.0. The number bears references from its Mesa heritage. Currently Mesa provides 17.2.x while 17.3.x should be the last version that ships the library. Some version numbers of wayland-egl.pc providers and users. The latter is taken from Ubuntu 17.04. Providers: - Mali: 7.10 - Mesa: 17.2.2 Users: - retroarch: NA - qtwayland5: NA - mpv, libmpv1: 9.0 - mesa-utils-extra: NA - weston, libweston-1-0: NA - libwaffle-1-0: 9.1 - libsdl2-2.0-0: NA - libgstreamer-plugins-bad1.0-0: autotools 9.0, meson 1.0 - libglfw3-wayland: NA - kwin-wayland, kwin-wayland-backend-wayland: NA? - glmark2-wayland, glmark2-es2-wayland: NA - libwebkit2gtk-4.0-37, libwebkit2gtk-4.0-37-gtk2, (webkit overall): NA - libgtk-3-0 (gtk overall): NA - libcogl20 (cogl overall): 1.0.0 v2: Bump the version to 17.4.0 Signed-off-by: Emil Velikov Reviewed-by: Arnaud Vrac --- egl/wayland-egl.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/egl/wayland-egl.pc.in b/egl/wayland-egl.pc.in index 8a40cfac..943442ee 100644 --- a/egl/wayland-egl.pc.in +++ b/egl/wayland-egl.pc.in @@ -4,8 +4,8 @@ libdir=@libdir@ includedir=@includedir@ Name: wayland-egl -Description: Mesa wayland-egl library -Version: @VERSION@ +Description: Frontend wayland-egl library +Version: 17.4.0 Requires: wayland-client Libs: -L${libdir} -lwayland-egl Cflags: -I${includedir} From bf3f9e241315cec472a482b5625c537d41dae6ab Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:46 +0100 Subject: [PATCH 0489/1152] wayland-egl: introduce wayland-egl-backend.pc File will be installed alongside the backend header. This way vendor implementations have enough information about the interface and they can build their backend/driver library accordingly. Cc: Miguel A. Vico Cc: James Jones Cc: Daniel Stone Cc: duncan-roe Cc: Takanari Hayama Signed-off-by: Emil Velikov Reviewed-by: Miguel A Vico Moya Reviewed-by: Arnaud Vrac --- egl/wayland-egl-backend.pc.in | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 egl/wayland-egl-backend.pc.in diff --git a/egl/wayland-egl-backend.pc.in b/egl/wayland-egl-backend.pc.in new file mode 100644 index 00000000..6cf0ed4d --- /dev/null +++ b/egl/wayland-egl-backend.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ + +Name: wayland-egl-backend +Description: Backend wayland-egl interface +Version: 3 +Libs: +Cflags: -I${includedir} From 066113a4c8cc6837519beab711d22cf01997ff11 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:47 +0100 Subject: [PATCH 0490/1152] wayland-egl: add a note about keeping the backend version in sync Signed-off-by: Emil Velikov Reviewed-by: Arnaud Vrac --- egl/wayland-egl-backend.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/egl/wayland-egl-backend.h b/egl/wayland-egl-backend.h index 82f025cb..3c23a56b 100644 --- a/egl/wayland-egl-backend.h +++ b/egl/wayland-egl-backend.h @@ -34,6 +34,10 @@ extern "C" { #endif +/* + * NOTE: This version must be kept in sync with the Version field in the + * wayland-egl-backend.pc.in file. + */ #define WL_EGL_WINDOW_VERSION 3 struct wl_surface; From 1fcb4d1387e2a40ed8cd35b11a7788de52b9cdb9 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:48 +0100 Subject: [PATCH 0491/1152] build: wire-up wayland-egl Wire-up the imported sources, test and pkg-config files. v2: - Don't mangle with existing EXTRA_DIST list - Add the symbols check script to the `make check' target - Rename wayland-egl-{priv,backend}.h Signed-off-by: Emil Velikov Reviewed-by: Arnaud Vrac --- Makefile.am | 22 ++++++++++++++++++++-- configure.ac | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1d21fa2b..1e934fec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,6 +119,7 @@ BUILT_SOURCES = \ CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db DISTCLEANFILES = src/wayland-version.h +EXTRA_DIST = @@ -143,6 +144,16 @@ libwayland_cursor_la_CFLAGS = \ -I$(top_srcdir)/src \ -DICONDIR=\"$(ICONDIR)\" +lib_LTLIBRARIES += libwayland-egl.la + +libwayland_egl_la_SOURCES = egl/wayland-egl.c +libwayland_egl_la_LDFLAGS = -version-info 1 + +pkgconfig_DATA += egl/wayland-egl.pc + +## XXX: backend interface +include_HEADERS += egl/wayland-egl-backend.h +pkgconfig_DATA += egl/wayland-egl-backend.pc built_test_programs = \ array-test \ @@ -164,7 +175,13 @@ built_test_programs = \ message-test \ headers-test \ compositor-introspection-test \ - protocol-logger-test + protocol-logger-test \ + wayland-egl-abi-check + +EXTRA_DIST += egl/wayland-egl-symbols-check + +check_PROGRAMS = wayland-egl-abi-check +wayland_egl_abi_check_SOURCES = egl/wayland-egl-abi-check.c if ENABLE_CPP_TEST built_test_programs += cpp-compile-test @@ -178,6 +195,7 @@ AM_TESTS_ENVIRONMENT = \ ; TESTS = $(built_test_programs) \ + egl/wayland-egl-symbols-check \ tests/scanner-test.sh noinst_PROGRAMS = \ @@ -263,7 +281,7 @@ os_wrappers_test_LDADD = libtest-runner.la exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c exec_fd_leak_checker_LDADD = libtest-runner.la -EXTRA_DIST = tests/scanner-test.sh \ +EXTRA_DIST += tests/scanner-test.sh \ protocol/tests.xml \ tests/data/example.xml \ tests/data/example-client.h \ diff --git a/configure.ac b/configure.ac index fcb9718b..25422439 100644 --- a/configure.ac +++ b/configure.ac @@ -193,6 +193,8 @@ AC_CONFIG_FILES([Makefile doc/publican/Makefile doc/doxygen/Makefile doc/man/Makefile + egl/wayland-egl.pc + egl/wayland-egl-backend.pc src/wayland-server-uninstalled.pc src/wayland-client-uninstalled.pc src/wayland-scanner-uninstalled.pc From 85cb5ed64aa8246f4da93fc5b76dfc34096bf803 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 10 Oct 2017 14:43:49 +0100 Subject: [PATCH 0492/1152] wayland-egl-symbols-check: pass the DSO name via the build system The location of the file is build system specific so, keep it there. Cc: Daniel Stone Suggested-by: Daniel Stone Signed-off-by: Emil Velikov Reviewed-by: Arnaud Vrac --- Makefile.am | 1 + egl/wayland-egl-symbols-check | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 1e934fec..deafc046 100644 --- a/Makefile.am +++ b/Makefile.am @@ -191,6 +191,7 @@ AM_TESTS_ENVIRONMENT = \ export WAYLAND_SCANNER='$(top_builddir)/wayland-scanner' \ TEST_DATA_DIR='$(top_srcdir)/tests/data' \ TEST_OUTPUT_DIR='$(top_builddir)/tests/output' \ + WAYLAND_EGL_LIB='$(top_builddir)/egl/.libs/libwayland-egl.so' \ SED=$(SED) \ ; diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index e7105ea5..e1073622 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -1,6 +1,6 @@ #!/bin/sh -FUNCS=$(nm -D --defined-only ${1-.libs/libwayland-egl.so} | grep -o "T .*" | cut -c 3- | while read func; do +FUNCS=$(nm -D --defined-only ${WAYLAND_EGL_LIB} | grep -o "T .*" | cut -c 3- | while read func; do ( grep -q "^$func$" || echo $func ) < Date: Tue, 10 Oct 2017 14:43:50 +0100 Subject: [PATCH 0493/1152] wayland-egl: move the wayland-egl{, -core}.h headers to egl/ Now we have all the wayland-egl bits in a single place. Signed-off-by: Emil Velikov Reviewed-by: Arnaud Vrac --- Makefile.am | 5 +++-- {src => egl}/wayland-egl-core.h | 0 {src => egl}/wayland-egl.h | 0 3 files changed, 3 insertions(+), 2 deletions(-) rename {src => egl}/wayland-egl-core.h (100%) rename {src => egl}/wayland-egl.h (100%) diff --git a/Makefile.am b/Makefile.am index deafc046..322d6b89 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,8 +64,6 @@ include_HEADERS = \ src/wayland-server-core.h \ src/wayland-client.h \ src/wayland-client-core.h \ - src/wayland-egl.h \ - src/wayland-egl-core.h \ src/wayland-version.h nodist_include_HEADERS = \ @@ -146,6 +144,9 @@ libwayland_cursor_la_CFLAGS = \ lib_LTLIBRARIES += libwayland-egl.la +include_HEADERS += egl/wayland-egl.h +include_HEADERS += egl/wayland-egl-core.h + libwayland_egl_la_SOURCES = egl/wayland-egl.c libwayland_egl_la_LDFLAGS = -version-info 1 diff --git a/src/wayland-egl-core.h b/egl/wayland-egl-core.h similarity index 100% rename from src/wayland-egl-core.h rename to egl/wayland-egl-core.h diff --git a/src/wayland-egl.h b/egl/wayland-egl.h similarity index 100% rename from src/wayland-egl.h rename to egl/wayland-egl.h From 9fa60983b5799be62b9d88a4059f4d0038d7c80d Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Wed, 13 Dec 2017 12:03:54 +0000 Subject: [PATCH 0494/1152] wayland-egl: rename wl_egl_window::private to driver_private MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit private is a reserved keyword in C++. Thus if one is to have a backend driver written in said language build will fail as below: .../wayland-egl-backend.h:56:8: expected unqualified-id before ‘private’ Rename it to driver_private and update the test. NOTE: version bump is not required since: - this is a pure API change, ABI is identical - hardware drivers already require [minor] changes to move to the upstream wayland-egl-backend.h Cc: Arnaud Vrac Cc: Miguel A . Vico Suggested-by: Arnaud Vrac Signed-off-by: Emil Velikov Reviewed-by: Miguel A Vico Moya --- egl/wayland-egl-abi-check.c | 6 +++--- egl/wayland-egl-backend.h | 2 +- egl/wayland-egl.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/egl/wayland-egl-abi-check.c b/egl/wayland-egl-abi-check.c index 62c51a22..faa6b572 100644 --- a/egl/wayland-egl-abi-check.c +++ b/egl/wayland-egl-abi-check.c @@ -91,7 +91,7 @@ struct wl_egl_window_v3 { int attached_width; int attached_height; - void *private; + void *driver_private; void (*resize_callback)(struct wl_egl_window *, void *); void (*destroy_window_callback)(void *); @@ -208,7 +208,7 @@ int main(int argc, char **argv) CHECK_MEMBER (_v2, _v3, dy); CHECK_MEMBER (_v2, _v3, attached_width); CHECK_MEMBER (_v2, _v3, attached_height); - CHECK_MEMBER (_v2, _v3, private); + CHECK_RENAMED_MEMBER(_v2, _v3, private, driver_private); CHECK_MEMBER (_v2, _v3, resize_callback); CHECK_MEMBER (_v2, _v3, destroy_window_callback); @@ -223,7 +223,7 @@ int main(int argc, char **argv) CHECK_MEMBER_CURRENT(_v3, dy); CHECK_MEMBER_CURRENT(_v3, attached_width); CHECK_MEMBER_CURRENT(_v3, attached_height); - CHECK_MEMBER_CURRENT(_v3, private); + CHECK_MEMBER_CURRENT(_v3, driver_private); CHECK_MEMBER_CURRENT(_v3, resize_callback); CHECK_MEMBER_CURRENT(_v3, destroy_window_callback); CHECK_MEMBER_CURRENT(_v3, surface); diff --git a/egl/wayland-egl-backend.h b/egl/wayland-egl-backend.h index 3c23a56b..869c86fd 100644 --- a/egl/wayland-egl-backend.h +++ b/egl/wayland-egl-backend.h @@ -53,7 +53,7 @@ struct wl_egl_window { int attached_width; int attached_height; - void *private; + void *driver_private; void (*resize_callback)(struct wl_egl_window *, void *); void (*destroy_window_callback)(void *); diff --git a/egl/wayland-egl.c b/egl/wayland-egl.c index 02ac04e8..a60f8991 100644 --- a/egl/wayland-egl.c +++ b/egl/wayland-egl.c @@ -49,7 +49,7 @@ wl_egl_window_resize(struct wl_egl_window *egl_window, egl_window->dy = dy; if (egl_window->resize_callback) - egl_window->resize_callback(egl_window, egl_window->private); + egl_window->resize_callback(egl_window, egl_window->driver_private); } WL_EXPORT struct wl_egl_window * @@ -89,7 +89,7 @@ WL_EXPORT void wl_egl_window_destroy(struct wl_egl_window *egl_window) { if (egl_window->destroy_window_callback) - egl_window->destroy_window_callback(egl_window->private); + egl_window->destroy_window_callback(egl_window->driver_private); free(egl_window); } From 68398ec2cec755651a4d97a134241427670a5f34 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 14 Feb 2018 12:15:11 -0600 Subject: [PATCH 0495/1152] connection: Fix broken log message when demarshalling short closure Like the similar wl_log() message further into this function that was fixed in commit 2fc248dc2c877d02694db40aad52180d71373d5a this should be printing the sender_id saved earlier instead of *p. Since p is incremented during the loop it would not only print an incorrect object id, it could read past the end of the array. Signed-off-by: Derek Foreman Reviewed-by: Pekka Paalanen --- src/connection.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index 5d5711f2..294c521a 100644 --- a/src/connection.c +++ b/src/connection.c @@ -710,7 +710,8 @@ wl_connection_demarshal(struct wl_connection *connection, if (arg.type != 'h' && p + 1 > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", - *p, message->name, message->signature); + closure->sender_id, message->name, + message->signature); errno = EINVAL; goto err; } From 76a4e4251c4e5db7b87fe2240573115e09ba143f Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 21 Feb 2017 16:14:29 +0000 Subject: [PATCH 0496/1152] build: remove white space in -uninstalled.pc.in files v2: Rebase, address wayland-client-uninstalled Signed-off-by: Emil Velikov Reviewed-by: Derek Foreman (v1) --- src/wayland-client-uninstalled.pc.in | 2 +- src/wayland-scanner-uninstalled.pc.in | 2 +- src/wayland-server-uninstalled.pc.in | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wayland-client-uninstalled.pc.in b/src/wayland-client-uninstalled.pc.in index 732736e9..6fd0ce6d 100644 --- a/src/wayland-client-uninstalled.pc.in +++ b/src/wayland-client-uninstalled.pc.in @@ -1,7 +1,7 @@ libdir=@abs_builddir@/.libs includedir=@abs_srcdir@ protocoldir=@abs_top_builddir@/protocol - + Name: Wayland Client Description: Wayland client side library (not installed) Version: @PACKAGE_VERSION@ diff --git a/src/wayland-scanner-uninstalled.pc.in b/src/wayland-scanner-uninstalled.pc.in index 132f42d0..45597998 100644 --- a/src/wayland-scanner-uninstalled.pc.in +++ b/src/wayland-scanner-uninstalled.pc.in @@ -1,6 +1,6 @@ pkgdatadir=@abs_top_srcdir@ wayland_scanner=@abs_top_builddir@/wayland-scanner - + Name: Wayland Scanner Description: Wayland scanner (not installed) Version: @PACKAGE_VERSION@ diff --git a/src/wayland-server-uninstalled.pc.in b/src/wayland-server-uninstalled.pc.in index 562686c3..6b6e6037 100644 --- a/src/wayland-server-uninstalled.pc.in +++ b/src/wayland-server-uninstalled.pc.in @@ -1,7 +1,7 @@ libdir=@abs_builddir@/.libs includedir=@abs_srcdir@ protocoldir=@abs_top_builddir@/protocol - + Name: Wayland Server Description: Server side implementation of the Wayland protocol (not installed) Version: @PACKAGE_VERSION@ From 9b76def674f0a0b99f5850cc800017fc4e03af7d Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 16 Feb 2018 16:22:30 +0000 Subject: [PATCH 0497/1152] scanner: introduce "public-code" and "private-code" The options are used to indicate how the code will be used - will it be public, as part of a DSO or private. In nearly every instance, people want to use the latter. One noticeable exception is the wayland libraries. They provide the base marshalling protocol that everyone uses. The option "code" was deprecated in favour of "public-code" with a warning message produced to guide people. Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen Reviewed-by: Derek Foreman --- src/scanner.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 1308fc7c..679e0068 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -57,15 +57,23 @@ enum side { SERVER, }; +enum visibility { + PRIVATE, + PUBLIC, +}; + static int usage(int ret) { - fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|code]" + fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|private-code|public-code]" " [input_file output_file]\n", PROGRAM_NAME); fprintf(stderr, "\n"); fprintf(stderr, "Converts XML protocol descriptions supplied on " "stdin or input file to client\n" - "headers, server headers, or protocol marshalling code.\n\n"); + "headers, server headers, or protocol marshalling code.\n\n" + "Use \"public-code\" only if the marshalling code will be public - " + "aka DSO will export it while other components will be using it.\n" + "Using \"private-code\" is strongly recommended.\n\n"); fprintf(stderr, "options:\n"); fprintf(stderr, " -h, --help display this help and exit.\n" " -v, --version print the wayland library version that\n" @@ -1714,9 +1722,11 @@ emit_messages(struct wl_list *message_list, printf("};\n\n"); } + static void -emit_code(struct protocol *protocol) +emit_code(struct protocol *protocol, enum visibility vis) { + const char *symbol_visibility; struct interface *i, *next; struct wl_array types; char **p, *prev; @@ -1730,6 +1740,19 @@ emit_code(struct protocol *protocol) "#include \n" "#include \"wayland-util.h\"\n\n"); + /* When building a shared library symbols must be exported, otherwise + * we want to have the symbols hidden. */ + if (vis == PRIVATE) { + symbol_visibility = "WL_PRIVATE"; + printf("#if defined(__GNUC__) && __GNUC__ >= 4\n" + "#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n" + "#else\n" + "#define WL_PRIVATE\n" + "#endif\n\n"); + } else { + symbol_visibility = "WL_EXPORT"; + } + wl_array_init(&types); wl_list_for_each(i, &protocol->interface_list, link) { emit_types_forward_declarations(protocol, &i->request_list, &types); @@ -1759,10 +1782,10 @@ emit_code(struct protocol *protocol) emit_messages(&i->request_list, i, "requests"); emit_messages(&i->event_list, i, "events"); - printf("WL_EXPORT const struct wl_interface " + printf("%s const struct wl_interface " "%s_interface = {\n" "\t\"%s\", %d,\n", - i->name, i->name, i->version); + symbol_visibility, i->name, i->name, i->version); if (!wl_list_empty(&i->request_list)) printf("\t%d, %s_requests,\n", @@ -1809,6 +1832,8 @@ int main(int argc, char *argv[]) enum { CLIENT_HEADER, SERVER_HEADER, + PRIVATE_CODE, + PUBLIC_CODE, CODE, } mode; @@ -1860,6 +1885,10 @@ int main(int argc, char *argv[]) mode = CLIENT_HEADER; else if (strcmp(argv[0], "server-header") == 0) mode = SERVER_HEADER; + else if (strcmp(argv[0], "private-code") == 0) + mode = PRIVATE_CODE; + else if (strcmp(argv[0], "public-code") == 0) + mode = PUBLIC_CODE; else if (strcmp(argv[0], "code") == 0) mode = CODE; else @@ -1947,8 +1976,17 @@ int main(int argc, char *argv[]) case SERVER_HEADER: emit_header(&protocol, SERVER); break; + case PRIVATE_CODE: + emit_code(&protocol, PRIVATE); + break; case CODE: - emit_code(&protocol); + fprintf(stderr, + "Using \"code\" is deprecated - use " + "private-code or public-code.\n" + "See the help page for details.\n"); + /* fallthrough */ + case PUBLIC_CODE: + emit_code(&protocol, PUBLIC); break; } From ab6b156920ced7dfac94e01cada216171b619891 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 16 Feb 2018 16:22:31 +0000 Subject: [PATCH 0498/1152] build: use public-code when using the local wayland-scanner The core wayland interfaces are public, via the libwayland-server and libwayland-client DSOs. Hence use "public-code" cmdline option, instead of the deprecated code". As the host wayland-scanner may not know about the new option, use the legacy "code". Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen Reviewed-by: Derek Foreman --- Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile.am b/Makefile.am index 322d6b89..4ffce0d7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -95,7 +95,11 @@ nodist_libwayland_client_la_SOURCES = \ pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml +if USE_HOST_SCANNER $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code $< $@ +else + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) public-code $< $@ +endif protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header $< $@ From bd92689382e5f401c6de26bdb8856cc3584f5c3a Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 16 Feb 2018 16:22:32 +0000 Subject: [PATCH 0499/1152] scanner: make use of __has_attribute() A more generic way to evaluating various attributes, __has_attribute is available with gcc, clang, even the Oracle/Sun compiler. Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen Reviewed-by: Derek Foreman --- src/scanner.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 679e0068..c93070c3 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1744,7 +1744,11 @@ emit_code(struct protocol *protocol, enum visibility vis) * we want to have the symbols hidden. */ if (vis == PRIVATE) { symbol_visibility = "WL_PRIVATE"; - printf("#if defined(__GNUC__) && __GNUC__ >= 4\n" + printf("#ifndef __has_attribute\n" + "# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */\n" + "#endif\n\n"); + + printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4\n" "#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n" "#else\n" "#define WL_PRIVATE\n" From b02c4013e3c10d26c6afae675eec77a97c4c10ab Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 22 Feb 2018 11:23:39 +0000 Subject: [PATCH 0500/1152] tests: add code, public-code and private-code tests First one is deprecated in favour of the second option. The latter is newly introduced and annotates the generated symbols accordingly. v2: Don't introduce small-public-code.c - reuse small-code.c (Pekka) Cc: Pekka Paalanen Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen Reviewed-by: Derek Foreman --- Makefile.am | 3 +- tests/data/small-private-code.c | 71 +++++++++++++++++++++++++++++++++ tests/scanner-test.sh | 4 ++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/data/small-private-code.c diff --git a/Makefile.am b/Makefile.am index 4ffce0d7..2731ee76 100644 --- a/Makefile.am +++ b/Makefile.am @@ -299,7 +299,8 @@ EXTRA_DIST += tests/scanner-test.sh \ tests/data/small-server.h \ tests/data/small-code-core.c \ tests/data/small-client-core.h \ - tests/data/small-server-core.h + tests/data/small-server-core.h \ + tests/data/small-private-code.c tests/scanner-test.sh: $(top_builddir)/wayland-scanner diff --git a/tests/data/small-private-code.c b/tests/data/small-private-code.c new file mode 100644 index 00000000..e447607b --- /dev/null +++ b/tests/data/small-private-code.c @@ -0,0 +1,71 @@ +/* SCANNER TEST */ + +/* + * Copyright © 2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4 +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface another_intf_interface; +extern const struct wl_interface intf_not_here_interface; + +static const struct wl_interface *types[] = { + NULL, + &intf_not_here_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &another_intf_interface, +}; + +static const struct wl_message intf_A_requests[] = { + { "rq1", "sun", types + 0 }, + { "rq2", "nsiufho", types + 1 }, + { "destroy", "", types + 0 }, +}; + +static const struct wl_message intf_A_events[] = { + { "hey", "", types + 0 }, +}; + +WL_PRIVATE const struct wl_interface intf_A_interface = { + "intf_A", 3, + 3, intf_A_requests, + 1, intf_A_events, +}; + diff --git a/tests/scanner-test.sh b/tests/scanner-test.sh index 7854b864..ff250894 100755 --- a/tests/scanner-test.sh +++ b/tests/scanner-test.sh @@ -48,4 +48,8 @@ generate_and_compare "-c code" "small.xml" "small-code-core.c" generate_and_compare "-c client-header" "small.xml" "small-client-core.h" generate_and_compare "-c server-header" "small.xml" "small-server-core.h" +# The existing "code" must produce result identical to "public-code" +generate_and_compare "code" "small.xml" "small-code.c" +generate_and_compare "public-code" "small.xml" "small-code.c" +generate_and_compare "private-code" "small.xml" "small-private-code.c" exit $RETCODE From 6903e4d5392563b36aabc8ebc69cb1a08dd2de0e Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 23 Feb 2018 17:31:53 +0000 Subject: [PATCH 0501/1152] wayland-egl: use correct `nm` path when cross-compiling Inspired by Heiko Becker and Eric's work in libdrm and Mesa respectively. Cc: Eric Engestrom Signed-off-by: Emil Velikov Reviewed-by: Daniel Stone --- configure.ac | 1 + egl/wayland-egl-symbols-check | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 25422439..91f837d0 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_PROG_CC AC_PROG_CXX AC_PROG_GREP AM_PROG_AS +AC_PROG_NM # check if we have C++ compiler. This is hacky workaround, # for a reason why it is this way see diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index e1073622..6ad28f39 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -1,6 +1,6 @@ #!/bin/sh -FUNCS=$(nm -D --defined-only ${WAYLAND_EGL_LIB} | grep -o "T .*" | cut -c 3- | while read func; do +FUNCS=$($NM -D --defined-only ${WAYLAND_EGL_LIB} | grep -o "T .*" | cut -c 3- | while read func; do ( grep -q "^$func$" || echo $func ) < Date: Fri, 23 Feb 2018 16:23:15 -0600 Subject: [PATCH 0502/1152] scanner: Fix broken private-code generation Missing a closing bracket. Reviewed-by: Daniel Stone --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index c93070c3..1737911b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1748,7 +1748,7 @@ emit_code(struct protocol *protocol, enum visibility vis) "# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */\n" "#endif\n\n"); - printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4\n" + printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)\n" "#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n" "#else\n" "#define WL_PRIVATE\n" From 400df40dfa8ec9095b0614a0be45dbea3f2a5895 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 26 Feb 2018 11:44:25 +0200 Subject: [PATCH 0503/1152] tests: fix scanner private-code test reference data Commit e501230d1dc8a5015616e104ec0e08886a0b88df "scanner: Fix broken private-code generation" changed the scanner output without updating the reference output for scanner tests. Update the reference data. This fixes 'make check'. Signed-off-by: Pekka Paalanen Reviewed-by: Derek Foreman --- tests/data/small-private-code.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/small-private-code.c b/tests/data/small-private-code.c index e447607b..5e0bc88f 100644 --- a/tests/data/small-private-code.c +++ b/tests/data/small-private-code.c @@ -33,7 +33,7 @@ # define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ #endif -#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4 +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) #define WL_PRIVATE __attribute__ ((visibility("hidden"))) #else #define WL_PRIVATE From 97351f995c216eff33b02ade0bd63dd089c3af89 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 26 Feb 2018 10:52:17 -0600 Subject: [PATCH 0504/1152] configure.ac: bump to version 1.14.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 91f837d0..a53b6cc6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [14]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From a9187853d44db41206b5d16a770d4db108972812 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 6 Mar 2018 17:38:13 -0600 Subject: [PATCH 0505/1152] client: Don't inappropriatly close fds for zombie objects commit 239ba39331420f953de35c337ae57db35573f9cb which was intended to stop leaking fds in events for zombie objects didn't notice that passing 0 to wl_connection_close_fds_in() would still close fds. Test the fd count before calling. Signed-off-by: Derek Foreman Reviewed-by: Daniel Stone --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index c1369b88..1ffa1f05 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1359,7 +1359,7 @@ queue_event(struct wl_display *display, int len) if (!proxy || wl_object_is_zombie(&display->objects, id)) { struct wl_zombie *zombie = wl_map_lookup(&display->objects, id); - if (zombie) + if (zombie && zombie->fd_count[opcode]) { wl_connection_close_fds_in(display->connection, zombie->fd_count[opcode]); From adda7cbbb894139d5a35abba41c310a433f693b9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 7 Mar 2018 13:38:53 -0600 Subject: [PATCH 0506/1152] walyand-client: Fix trivial build break from previous commit previous commit, a9187853d44db41206b5d16a770d4db108972812 added a trailing { on a line it shouldn't have, and I pushed without building first. Signed-off-by: Derek Foreman --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 1ffa1f05..efeb7450 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1359,7 +1359,7 @@ queue_event(struct wl_display *display, int len) if (!proxy || wl_object_is_zombie(&display->objects, id)) { struct wl_zombie *zombie = wl_map_lookup(&display->objects, id); - if (zombie && zombie->fd_count[opcode]) { + if (zombie && zombie->fd_count[opcode]) wl_connection_close_fds_in(display->connection, zombie->fd_count[opcode]); From 371c26d52b992ed224062cb09e138d0c053b87ff Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 14 Feb 2018 14:22:23 +0200 Subject: [PATCH 0507/1152] tests: disable coredumps on sanity-test SEGV and ABRT by default cause a core dump, which may create a file, launch crash handlers, and so on. sanity-test has 21 processes that are expected to crash like this. Disable core dumps on them all. I counted 21 entries in coredumpctl list, while only 16 functions needed patching. After this patch no entries appear in coredumpctl list. Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone --- configure.ac | 3 ++- tests/sanity-test.c | 18 ++++++++++++++++++ tests/test-helpers.c | 30 ++++++++++++++++++++++++++++++ tests/test-runner.h | 3 +++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a53b6cc6..674695d5 100644 --- a/configure.ac +++ b/configure.ac @@ -62,7 +62,8 @@ if test "x$GCC" = "xyes"; then fi AC_SUBST(GCC_CFLAGS) -AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate]) +AC_CHECK_HEADERS([sys/prctl.h]) +AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl]) AC_ARG_ENABLE([libraries], [AC_HELP_STRING([--disable-libraries], diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 7a93da32..66ca16fb 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -53,11 +53,13 @@ FAIL_TEST(exit_failure) FAIL_TEST(fail_abort) { + test_disable_coredumps(); abort(); } FAIL_TEST(fail_wl_abort) { + test_disable_coredumps(); wl_abort("Abort the program\n"); } @@ -68,11 +70,13 @@ FAIL_TEST(fail_kill) FAIL_TEST(fail_segv) { + test_disable_coredumps(); * (char **) 0 = "Goodbye, world"; } FAIL_TEST(sanity_assert) { + test_disable_coredumps(); /* must fail */ assert(0); } @@ -87,6 +91,7 @@ FAIL_TEST(sanity_malloc_direct) assert(p); /* assert that we got memory, also prevents * the malloc from getting optimized away. */ free(NULL); /* NULL must not be counted */ + test_disable_coredumps(); } TEST(disable_leak_checks) @@ -114,6 +119,8 @@ FAIL_TEST(sanity_malloc_indirect) wl_array_add(&array, 14); /* not freeing array, must leak */ + + test_disable_coredumps(); } FAIL_TEST(tc_client_memory_leaks) @@ -121,6 +128,7 @@ FAIL_TEST(tc_client_memory_leaks) struct display *d = display_create(); client_create_noarg(d, sanity_malloc_direct); display_run(d); + test_disable_coredumps(); display_destroy(d); } @@ -129,6 +137,7 @@ FAIL_TEST(tc_client_memory_leaks2) struct display *d = display_create(); client_create_noarg(d, sanity_malloc_indirect); display_run(d); + test_disable_coredumps(); display_destroy(d); } @@ -141,6 +150,8 @@ FAIL_TEST(sanity_fd_leak) /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ + + test_disable_coredumps(); } FAIL_TEST(sanity_fd_leak_exec) @@ -152,6 +163,7 @@ FAIL_TEST(sanity_fd_leak_exec) if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ + test_disable_coredumps(); exec_fd_leak_check(nr_fds); } @@ -212,6 +224,7 @@ FAIL_TEST(tc_client_fd_leaks) client_create_noarg(d, sanity_fd_leak); display_run(d); + test_disable_coredumps(); display_destroy(d); } @@ -222,12 +235,14 @@ FAIL_TEST(tc_client_fd_leaks_exec) client_create_noarg(d, sanity_fd_leak); display_run(d); + test_disable_coredumps(); display_destroy(d); } FAIL_TEST(timeout_tst) { test_set_timeout(1); + test_disable_coredumps(); /* test should reach timeout */ test_sleep(2); } @@ -247,6 +262,7 @@ FAIL_TEST(timeout_reset_tst) test_set_timeout(10); test_set_timeout(1); + test_disable_coredumps(); /* test should fail on timeout */ test_sleep(2); } @@ -265,6 +281,7 @@ FAIL_TEST(tc_timeout_tst) struct display *d = display_create(); client_create_noarg(d, timeout_tst); display_run(d); + test_disable_coredumps(); display_destroy(d); } @@ -273,6 +290,7 @@ FAIL_TEST(tc_timeout2_tst) struct display *d = display_create(); client_create_noarg(d, timeout_reset_tst); display_run(d); + test_disable_coredumps(); display_destroy(d); } diff --git a/tests/test-helpers.c b/tests/test-helpers.c index a9900036..b2189d8e 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -23,12 +23,20 @@ * SOFTWARE. */ +#include "config.h" + #include #include #include #include #include #include +#include +#include + +#ifdef HAVE_SYS_PRCTL_H +#include +#endif #include "test-runner.h" @@ -97,3 +105,25 @@ test_sleep(unsigned int sec) assert(nanosleep(&ts, NULL) == 0); } + +/** Try to disable coredumps + * + * Useful for tests that crash on purpose, to avoid creating a core file + * or launching an application crash handler service or cluttering coredumpctl. + * + * NOTE: Calling this may make the process undebuggable. + */ +void +test_disable_coredumps(void) +{ + struct rlimit r; + + if (getrlimit(RLIMIT_CORE, &r) == 0) { + r.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &r); + } + +#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) + prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); +#endif +} diff --git a/tests/test-runner.h b/tests/test-runner.h index 81ed0343..9c47a2b0 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -86,6 +86,9 @@ test_usleep(useconds_t); void test_sleep(unsigned int); +void +test_disable_coredumps(void); + #define DISABLE_LEAK_CHECKS \ do { \ extern int leak_check_enabled; \ From f34af17b219f1eaa0d091a687124fbb8b7a3c81b Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 13 Mar 2018 13:43:37 +0000 Subject: [PATCH 0508/1152] configure.ac: don't install the static libraries One should always be using the shared libraries. Spotted while going through the Debian packaing. Signed-off-by: Emil Velikov Reviewed-by: Peter Hutterer Acked-by: Pekka Paalanen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 674695d5..363c8337 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ AM_CONDITIONAL(ENABLE_CPP_TEST, test "x$have_cpp_compiler" = "xyes") # Initialize libtool LT_PREREQ([2.2]) -LT_INIT +LT_INIT([disable-static]) PKG_PROG_PKG_CONFIG() From 79cc3ad6bd0d7c19b64def8b4e4fea0483993dc6 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 16 Mar 2018 16:14:54 +0000 Subject: [PATCH 0509/1152] wayland-egl: set the correct path to libwayland-egl.so Earlier commit changed to passing the binary name as env. variable introducing a typo. That went unnoticed, since we do not check if the file is present or not. Cc: Pukka Paalanen Cc: Daniel Stone Fixes: 85cb5ed64aa ("wayland-egl-symbols-check: pass the DSO name via the build system") Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 2731ee76..6f59c369 100644 --- a/Makefile.am +++ b/Makefile.am @@ -196,7 +196,7 @@ AM_TESTS_ENVIRONMENT = \ export WAYLAND_SCANNER='$(top_builddir)/wayland-scanner' \ TEST_DATA_DIR='$(top_srcdir)/tests/data' \ TEST_OUTPUT_DIR='$(top_builddir)/tests/output' \ - WAYLAND_EGL_LIB='$(top_builddir)/egl/.libs/libwayland-egl.so' \ + WAYLAND_EGL_LIB='$(top_builddir)/.libs/libwayland-egl.so' \ SED=$(SED) \ ; From 2ba70f1f6de52e207aad82680bd4f794d7b99e52 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 15 Mar 2018 14:30:27 +0000 Subject: [PATCH 0510/1152] wayland-egl: fail the symbol check if lib is missing Based on a similar patch (in Mesa) by Eric Engestrom. v2: Rebase on top of $NM patch v3: Rebase Reviewed-by: Eric Engestrom (v1) Signed-off-by: Emil Velikov Reviewed-by: Daniel Stone --- egl/wayland-egl-symbols-check | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index 6ad28f39..8b3d7113 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -1,6 +1,14 @@ #!/bin/sh +set -eu -FUNCS=$($NM -D --defined-only ${WAYLAND_EGL_LIB} | grep -o "T .*" | cut -c 3- | while read func; do +LIB=${WAYLAND_EGL_LIB} + +if [ ! -f "$LIB" ]; then + echo "The test binary \"$LIB\" does no exist" + exit 1 +fi + +FUNCS=$($NM -D --defined-only $LIB | grep -o "T .*" | cut -c 3- | while read func; do ( grep -q "^$func$" || echo $func ) < Date: Thu, 15 Mar 2018 14:30:28 +0000 Subject: [PATCH 0511/1152] wayland-egl: enhance the symbol test The current test had a few fall-outs: - it was checking only for T (.text) symbols - did not consider symbol removal Fix that by fetching all the symbols and doing a bidirectional check - for added and removed symbols. Error out with informative message for each case. v2: Rebase on top of $NM patch. Signed-off-by: Emil Velikov Reviewed-by: Daniel Stone --- egl/wayland-egl-symbols-check | 36 +++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index 8b3d7113..c47026b2 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -8,17 +8,37 @@ if [ ! -f "$LIB" ]; then exit 1 fi -FUNCS=$($NM -D --defined-only $LIB | grep -o "T .*" | cut -c 3- | while read func; do -( grep -q "^$func$" || echo $func ) < Date: Thu, 15 Mar 2018 14:30:29 +0000 Subject: [PATCH 0512/1152] wayland-egl: bump the version number to 18.1.0 Seems like I was overoptimistic with my earlier assumption, namely: "... 17.3.x should be the last version that ships the library." Mesa 18.0.0 and its wayland-egl is about to be released any time soon, so bump the number since it must no be smaller. As soon as we get a wayland release I'll drop the Mesa copy but for now. Signed-off-by: Emil Velikov Reviewed-by: Daniel Stone --- egl/wayland-egl.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/egl/wayland-egl.pc.in b/egl/wayland-egl.pc.in index 943442ee..2e2d4c49 100644 --- a/egl/wayland-egl.pc.in +++ b/egl/wayland-egl.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: wayland-egl Description: Frontend wayland-egl library -Version: 17.4.0 +Version: 18.1.0 Requires: wayland-client Libs: -L${libdir} -lwayland-egl Cflags: -I${includedir} From 2031bcf5daef57d1693b5e808fac2bb90affe5cb Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 19 Mar 2018 12:20:54 +0000 Subject: [PATCH 0513/1152] wayland-egl: Pass nm path to check script A previous patch used $NM as an environment variable, but this was only set as a make variable. Make sure it is passed through from make to the environment we use to run tests. v2: Quote argument when passing to shell. Signed-off-by: Daniel Stone Reported-by: Pekka Paalanen Fixes: 6903e4d53925 ("wayland-egl: use correct `nm` path when cross-compiling") Cc: Emil Velikov Reviewed-by: Quentin Glidic --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 6f59c369..741db5eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -198,6 +198,7 @@ AM_TESTS_ENVIRONMENT = \ TEST_OUTPUT_DIR='$(top_builddir)/tests/output' \ WAYLAND_EGL_LIB='$(top_builddir)/.libs/libwayland-egl.so' \ SED=$(SED) \ + NM='$(NM)' \ ; TESTS = $(built_test_programs) \ From 3de11b8d798d657fb59e84792a44dbb027ab523f Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 19 Mar 2018 15:13:14 +0000 Subject: [PATCH 0514/1152] wayland-egl: Make symbol test fail on failure The previous rewrite of the wayland-egl ABI checker introduced checks for removed symbols as well as added symbols, but broke some failure conditions. Add an explict return-code variable set in failure paths, rather than chaining or conditions. If we cannot find the binary or nm, we regard this as an error condition, rather than test failure. v2: Don't test if we can execute $NM. Signed-off-by: Daniel Stone Reported-by: Pekka Paalanen Fixes: 21b1f22eb056 ("wayland-egl: enhance the symbol test") Cc: Emil Velikov Reviewed-by: Emil Velikov --- egl/wayland-egl-symbols-check | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index c47026b2..70fe1f4c 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -1,11 +1,17 @@ #!/bin/sh set -eu +RET=0 LIB=${WAYLAND_EGL_LIB} -if [ ! -f "$LIB" ]; then - echo "The test binary \"$LIB\" does no exist" - exit 1 +if ! test -f "$LIB"; then + echo "Test binary \"$LIB\" does not exist" + exit 99 +fi + +if ! test -n "$NM"; then + echo "nm environment variable not set" + exit 99 fi AVAIL_FUNCS="$($NM -D --format=bsd --defined-only $LIB | awk '{print $3}')" @@ -32,7 +38,11 @@ NEW_ABI=$(echo "$AVAIL_FUNCS" | while read func; do echo $func done) -test ! -n "$NEW_ABI" || echo "New ABI detected - If intentional, update the test."; echo "$NEW_ABI" +if test -n "$NEW_ABI"; then + echo "New ABI detected - If intentional, update the test." + echo "$NEW_ABI" + RET=1 +fi REMOVED_ABI=$(echo "$REQ_FUNCS" | while read func; do echo "$AVAIL_FUNCS" | grep -q "^$func$" && continue @@ -40,5 +50,10 @@ REMOVED_ABI=$(echo "$REQ_FUNCS" | while read func; do echo $func done) -test ! -n "$REMOVED_ABI" || echo "ABI break detected - Required symbol(s) no longer exported!"; echo "$REMOVED_ABI" -test ! -n "$NEW_ABI" || test ! -n "$REMOVED_ABI" +if test -n "$REMOVED_ABI"; then + echo "ABI break detected - Required symbol(s) no longer exported!" + echo "$REMOVED_ABI" + RET=1 +fi + +exit $RET From d3fe626219ee336d86f1bec980c5c09cce8d68c1 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 19 Mar 2018 15:39:39 -0500 Subject: [PATCH 0515/1152] configure.ac: bump to version 1.14.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 363c8337..c4eb7711 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [14]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 05fd07f4277414ae39a0336ac04c94a58ef2aa96 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 20 Mar 2018 11:01:02 +0000 Subject: [PATCH 0516/1152] wayland-egl: Ignore underscored symbols in ABI check Rather than a hard-coded list of platform symbols, just ignore anything prefaced with an underscore. This fixes breakage on ARM, which declares several slightly different platform symbols to x86. Signed-off-by: Daniel Stone Fixes: 21b1f22eb056 ("wayland-egl: enhance the symbol test") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105620 Cc: Emil Velikov Reviewed-by: Derek Foreman --- egl/wayland-egl-symbols-check | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index 70fe1f4c..d04fd042 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -16,14 +16,6 @@ fi AVAIL_FUNCS="$($NM -D --format=bsd --defined-only $LIB | awk '{print $3}')" -# Platform specific symbols. -PLAT_FUNCS="__bss_start -_edata -_end -_fini -_init -" - # Official ABI, taken from the header. REQ_FUNCS="wl_egl_window_resize wl_egl_window_create @@ -32,8 +24,8 @@ wl_egl_window_get_attached_size " NEW_ABI=$(echo "$AVAIL_FUNCS" | while read func; do + echo "$func" | grep -q "^_" && continue echo "$REQ_FUNCS" | grep -q "^$func$" && continue - echo "$PLAT_FUNCS" | grep -q "^$func$" && continue echo $func done) From dbcd4cd96e60a7d0fed3916aa6691a5aa681114b Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Tue, 20 Mar 2018 11:10:45 +0000 Subject: [PATCH 0517/1152] .gitignore: add wayland-egl-abi-check Instruct git go ignore the file, in case we've done an in-tree build. Cc: Derek Foreman Signed-off-by: Emil Velikov Reviewed-by: Derek Foreman --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8da9861b..eadea12e 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,6 @@ Makefile Makefile.in exec-fd-leak-checker fixed-benchmark +/wayland-egl-abi-check /wayland-scanner protocol/*.[ch] From 8be9aa86a2fd0f00f842c4a700633f3521fa9704 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 2 Apr 2018 12:50:16 -0500 Subject: [PATCH 0518/1152] configure.ac: bump to version 1.14.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c4eb7711..67fe819d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [14]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 4fdb8530a3dfd43cdd88e89188a7eb468bf8d07c Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 9 Apr 2018 11:54:10 -0500 Subject: [PATCH 0519/1152] configure.ac: bump to version 1.15.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 67fe819d..102d258e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [14]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [15]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From e09c1a98f988d32f8b6fb06aa72da06c93897189 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 9 Apr 2018 13:15:31 -0500 Subject: [PATCH 0520/1152] configure.ac: Reopen master for regular development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 102d258e..c74ee97b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [15]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 685f9a09097a7c598dd737eb83ea419f6a21b260 Mon Sep 17 00:00:00 2001 From: Dipen Somani Date: Thu, 19 Apr 2018 09:01:56 -0500 Subject: [PATCH 0521/1152] wayland-server: Properly handle EAGAIN from wl_connection_read() commit 3cddb3c692acd3536a7cc8542a29f0cc3c0ac3d6 casted len to an unsigned value to compare to sizeof results. However, wl_connection_read() can fail, setting errno to EAGAIN and returning a value of -1. When cast to an unsigned type this leads to a loop condition of true when it should be false. Signed-off-by: Dipen Somani Signed-off-by: Derek Foreman Reviewed-by: Derek Foreman --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index eb1e5000..eab2ee45 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -353,7 +353,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) } } - while ((size_t) len >= sizeof p) { + while (len >= 0 && (size_t) len >= sizeof p) { wl_connection_copy(connection, p, sizeof p); opcode = p[1] & 0xffff; size = p[1] >> 16; From 58ee271bff499b6b0d865fa0126990dc478bff24 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 16 Apr 2018 15:00:58 -0500 Subject: [PATCH 0522/1152] tests: Test for use after free in resource destruction signals For years it's been common practice to free the object containing the wl_listener inside resource destruction notifiers, but not remove the listener from the list. That is: It's been safe to assume (when only one listener is present) that the wl_listener will never be touched again, since this is a destruction callback. Recently some patches were reviewed that made some positive changes to our internal signal handling code, but would've violated this assumption, and changed free()d memory in several existing compositors (weston, mutter, enlightenment). Since the breakage was extremely subtle, codify this assumption in a test case (thus promoting it to an ABI promise). Reviewed-by: Pekka Paalanen Reviewed-by: Markus Ongyerth Signed-off-by: Derek Foreman --- tests/resources-test.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/resources-test.c b/tests/resources-test.c index 59d8beb7..76c9eb89 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -84,6 +84,17 @@ destroy_notify(struct wl_listener *l, void *data) { assert(l && data); notify_called = 1; + + /* In real code it's common to free the structure holding the + * listener at this point, but not to remove it from the list. + * + * That's fine since this is a destruction notification and + * it's the last time this signal can fire. We set these + * to NULL so we can check them later to ensure no write after + * "free" occurred. + */ + l->link.prev = NULL; + l->link.next = NULL; } TEST(destroy_res_tst) @@ -119,6 +130,8 @@ TEST(destroy_res_tst) assert(destroyed); assert(notify_called); /* check if signal was emitted */ assert(wl_client_get_object(client, id) == NULL); + assert(destroy_listener.link.prev == NULL); + assert(destroy_listener.link.next == NULL); res = wl_resource_create(client, &wl_seat_interface, 2, 0); assert(res); @@ -131,6 +144,8 @@ TEST(destroy_res_tst) wl_client_destroy(client); assert(destroyed); assert(notify_called); + assert(destroy_listener.link.prev == NULL); + assert(destroy_listener.link.next == NULL); wl_display_destroy(display); close(s[1]); From 5e0f7ad1bfcaadcc9cfaa1bd3fa78a1442b873a2 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Mon, 16 Apr 2018 15:00:59 -0500 Subject: [PATCH 0523/1152] server: Add special case destroy signal emitter In the past much code (weston, efl/enlightenment, mutter) has freed structures containing wl_listeners from destroy handlers without first removing the listener from the signal. As the destroy notifier only fires once, this has largely gone unnoticed until recently. Other code does not (Qt, wlroots) - and removes itself from the signal before free. If somehow a destroy signal is listened to by code from both kinds of callers, those that free will corrupt the lists for those that don't, and Bad Things will happen. To avoid these bad things, remove every item from the signal list during destroy emit, and put it in a list all its own. This way whether the listener is removed or not has no impact on the following emits. Signed-off-by: Derek Foreman Reviewed-by: Simon Ser Reviewed-by: Markus Ongyerth --- src/wayland-private.h | 3 +++ src/wayland-server.c | 46 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index 12b9032c..29516ec9 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -253,6 +253,9 @@ wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify); void wl_priv_signal_emit(struct wl_priv_signal *signal, void *data); +void +wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data); + void wl_connection_close_fds_in(struct wl_connection *connection, int max); diff --git a/src/wayland-server.c b/src/wayland-server.c index eab2ee45..eae8d2e7 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -682,7 +682,7 @@ destroy_resource(void *element, void *data, uint32_t flags) /* Don't emit the new signal for deprecated resources, as that would * access memory outside the bounds of the deprecated struct */ if (!resource_is_deprecated(resource)) - wl_priv_signal_emit(&resource->destroy_signal, resource); + wl_priv_signal_final_emit(&resource->destroy_signal, resource); if (resource->destroy) resource->destroy(resource); @@ -841,7 +841,7 @@ wl_client_destroy(struct wl_client *client) { uint32_t serial = 0; - wl_priv_signal_emit(&client->destroy_signal, client); + wl_priv_signal_final_emit(&client->destroy_signal, client); wl_client_flush(client); wl_map_for_each(&client->objects, destroy_resource, &serial); @@ -1089,7 +1089,7 @@ wl_display_destroy(struct wl_display *display) struct wl_socket *s, *next; struct wl_global *global, *gnext; - wl_priv_signal_emit(&display->destroy_signal, display); + wl_priv_signal_final_emit(&display->destroy_signal, display); wl_list_for_each_safe(s, next, &display->socket_list, link) { wl_socket_destroy(s); @@ -2025,6 +2025,46 @@ wl_priv_signal_emit(struct wl_priv_signal *signal, void *data) } } +/** Emit the signal for the last time, calling all the installed listeners + * + * Iterate over all the listeners added to this \a signal and call + * their \a notify function pointer, passing on the given \a data. + * Removing or adding a listener from within wl_priv_signal_emit() + * is safe, as is freeing the structure containing the listener. + * + * A large body of external code assumes it's ok to free a destruction + * listener without removing that listener from the list. Mixing code + * that acts like this and code that doesn't will result in list + * corruption. + * + * We resolve this by removing each item from the list and isolating it + * in another list. We discard it completely after firing the notifier. + * This should allow interoperability between code that unlinks its + * destruction listeners and code that just frees structures they're in. + * + */ +void +wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data) +{ + struct wl_listener *l; + struct wl_list *pos; + + /* During a destructor notifier isolate every list item before + * notifying. This renders harmless the long standing misuse + * of freeing listeners without removing them, but allows + * callers that do choose to remove them to interoperate with + * ones that don't. */ + while (!wl_list_empty(&signal->listener_list)) { + pos = signal->listener_list.next; + l = wl_container_of(pos, l, link); + + wl_list_remove(pos); + wl_list_init(pos); + + l->notify(l, data); + } +} + /** \endcond INTERNAL */ /** \cond */ /* Deprecated functions below. */ From 0e6ac72288f884ba0321c285a65578492c706534 Mon Sep 17 00:00:00 2001 From: Markus Ongyerth Date: Mon, 16 Apr 2018 15:01:00 -0500 Subject: [PATCH 0524/1152] tests: Add free-without-remove test [Derek Foreman moved this into resources-test] Reviewed-by: Derek Foreman --- tests/resources-test.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/resources-test.c b/tests/resources-test.c index 76c9eb89..fa6ba2b2 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -182,3 +182,27 @@ TEST(create_resource_with_same_id) wl_display_destroy(display); close(s[1]); } + +static void +display_destroy_notify(struct wl_listener *l, void *data) +{ + l->link.prev = l->link.next = NULL; +} + +TEST(free_without_remove) +{ + struct wl_display *display; + struct wl_listener a, b; + + display = wl_display_create(); + a.notify = display_destroy_notify; + b.notify = display_destroy_notify; + + wl_display_add_destroy_listener(display, &a); + wl_display_add_destroy_listener(display, &b); + + wl_display_destroy(display); + + assert(a.link.next == a.link.prev && a.link.next == NULL); + assert(b.link.next == b.link.prev && b.link.next == NULL); +} From a060822399b8f38ca665b502c6fb4c204029c5e8 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 5 Jun 2018 21:22:38 +0100 Subject: [PATCH 0525/1152] Add .gitlab-ci.yml Add a GitLab CI configuration which tests building, 'make check', and 'make distcheck' of the tree inside a Debian Stretch container. The choice of distribution base was arbitrary and may easily be changed. When commits are pushed to upstream, the commits will run this CI pipeline to run these tests, and capture the result as an artifact bundle, including the compiled binaries and full test suite logs. Results can be seen at: https://gitlab.freedesktop.org/wayland/wayland/pipelines/ Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..bc1a005a --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,35 @@ +image: debian:stretch + +stages: + - build + +before_script: + - echo 'path-exclude=/usr/share/doc/*' > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft + - echo 'path-exclude=/usr/share/man/*' >> /etc/dpkg/dpkg.cfg.d/99-exclude-cruft + - echo '#!/bin/sh' > /usr/sbin/policy-rc.d + - echo 'exit 101' >> /usr/sbin/policy-rc.d + - chmod +x /usr/sbin/policy-rc.d + - apt-get update + - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl + +build-native: + stage: build + script: + - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" + - export PREFIX="$(pwd)/prefix-$BUILD_ID" + - export BUILDDIR="$(pwd)/build-$BUILD_ID" + - export MAKEFLAGS="-j4" + - mkdir "$BUILDDIR" "$PREFIX" + - cd "$BUILDDIR" + - ../autogen.sh --prefix="$PREFIX" --with-icondir=/usr/share/X11/icons + - make all + - make check + - make install + - make distcheck + artifacts: + name: wayland-$CI_COMMIT_SHA-$CI_JOB_ID + when: always + paths: + - build-*/wayland-*.tar.xz + - build-*/*.log + - prefix-* From 8b2ba84bd0c152d3e6de8bd22b413a1ca6eb6630 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 25 May 2018 17:24:41 -0400 Subject: [PATCH 0526/1152] scanner: allow referencing foreign enums It's already possible to reference foreign interfaces, so it should also be possible to reference foreign enums. Signed-off-by: Simon Ser Reviewed-by: Silvan Jegen Reviewed-by: Pekka Paalanen --- src/scanner.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 1737911b..205c28a9 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -894,14 +894,9 @@ verify_arguments(struct parse_context *ctx, e = find_enumeration(ctx->protocol, interface, a->enumeration_name); - if (e == NULL) - fail(&ctx->loc, - "could not find enumeration %s", - a->enumeration_name); - switch (a->type) { case INT: - if (e->bitfield) + if (e && e->bitfield) fail(&ctx->loc, "bitfield-style enum must only be referenced by uint"); break; From 7846d4beea05239f7188f8417e8f497203bf8641 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Sat, 9 Jun 2018 00:49:33 +0100 Subject: [PATCH 0527/1152] doc: Update URLs for GitLab transition Update bug and Git URLs for GitLab; the site has also been served over HTTPS for quite some time. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen --- README | 4 ++-- configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 63ffa31d..3ae9f0fc 100644 --- a/README +++ b/README @@ -24,12 +24,12 @@ clients. Building the wayland libraries is fairly simple, aside from libffi, they don't have many dependencies: - $ git clone git://anongit.freedesktop.org/wayland/wayland + $ git clone https://gitlab.freedesktop.org/wayland/wayland $ cd wayland $ ./autogen.sh --prefix=PREFIX $ make $ make install where PREFIX is where you want to install the libraries. See -http://wayland.freedesktop.org for more complete build instructions +https://wayland.freedesktop.org for more complete build instructions for wayland, weston, xwayland and various toolkits. diff --git a/configure.ac b/configure.ac index c74ee97b..d0a10e17 100644 --- a/configure.ac +++ b/configure.ac @@ -8,9 +8,9 @@ m4_define([wayland_version], AC_INIT([wayland], [wayland_version], - [https://bugs.freedesktop.org/enter_bug.cgi?product=Wayland&component=wayland&version=wayland_version], + [https://gitlab.freedesktop.org/wayland/wayland/issues/], [wayland], - [http://wayland.freedesktop.org/]) + [https://wayland.freedesktop.org/]) AC_SUBST([WAYLAND_VERSION_MAJOR], [wayland_major_version]) AC_SUBST([WAYLAND_VERSION_MINOR], [wayland_minor_version]) From d95cf312019bed4768a2e97ec73dc926eddc4dbe Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 13 Jun 2018 12:45:36 +0300 Subject: [PATCH 0528/1152] doc: move Contributing Gitlab expects a CONTRIBUTING.md in the root directory, so move our guide there. Conversion to proper markup is a follow-up patch. Signed-off-by: Pekka Paalanen Reviewed-by: Peter Hutterer Reviewed-by: Daniel Stone --- doc/Contributing => CONTRIBUTING.md | 0 Makefile.am | 2 +- doc/Makefile.am | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) rename doc/Contributing => CONTRIBUTING.md (100%) diff --git a/doc/Contributing b/CONTRIBUTING.md similarity index 100% rename from doc/Contributing rename to CONTRIBUTING.md diff --git a/Makefile.am b/Makefile.am index 741db5eb..697c517b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -121,7 +121,7 @@ BUILT_SOURCES = \ CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db DISTCLEANFILES = src/wayland-version.h -EXTRA_DIST = +EXTRA_DIST = CONTRIBUTING.md diff --git a/doc/Makefile.am b/doc/Makefile.am index 14637af6..1efd3e28 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,3 +1 @@ SUBDIRS = doxygen publican man - -EXTRA_DIST = Contributing From 630c25f4c1609c0be1c0cdfcb4a9d125ac8c2d14 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 13 Jun 2018 13:21:43 +0300 Subject: [PATCH 0529/1152] contributing: format as markdown Format for nice viewing through Gitlab. Conduct and Licensing were raised to first level headings as they are not technical guidelines for contributing patches. It's nice to use the first level headings more. Reformat patchwork link and add Xorg patchwork link for Xwayland. v2: Unfortunately Gitlab harcodes a tab character to mean 4 spaces, so we cannot reasonably spell the coding style examples correctly. Hence, tab characters have been replaced with eight spaces so that they at least look right in both the file and through gitlab web UI. Signed-off-by: Pekka Paalanen Reviewed-by: Peter Hutterer Reviewed-by: Daniel Stone --- CONTRIBUTING.md | 152 +++++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9475271a..7ad75b87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,11 @@ -= Contributing to Wayland = +Contributing to Wayland +======================= -== Sending patches == +Sending patches +--------------- -Patches should be sent to wayland-devel@lists.freedesktop.org, using -git send-email. See git's documentation for help [1]. +Patches should be sent to **wayland-devel@lists.freedesktop.org**, using +`git send-email`. See [git documentation] for help. The first line of a commit message should contain a prefix indicating what part is affected by the patch followed by one sentence that @@ -28,7 +30,8 @@ answered on the one-line summary. The lines of the commit message should have at most 76 characters, to cope with the way git log presents them. -See [2] for a recommended reading on writing commit messages. +See [notes on commit messages] for a recommended reading on writing commit +messages. Your patches should also include a Signed-off-by line with your name and email address. If you're not the patch's original author, you should @@ -40,15 +43,14 @@ responsibility for the copyright status of the code. We won't reject patches that lack S-o-b, but it is strongly recommended. -== Tracking patches and following up == +Tracking patches and following up +--------------------------------- -Patchwork is used for tracking patches to Wayland and Weston: -http://patchwork.freedesktop.org/project/wayland/list/ - -Xwayland patches are tracked with the Xorg project, not here. - -Libinput patches, even though they use the same mailing list as Wayland, are -not tracked in the Wayland Patchwork. +[Wayland Patchwork](http://patchwork.freedesktop.org/project/wayland/list/) is +used for tracking patches to Wayland and Weston. Xwayland patches are tracked +with the [Xorg project](https://patchwork.freedesktop.org/project/Xorg/list/) +instead. Libinput patches, even though they use the same mailing list as +Wayland, are not tracked in the Wayland Patchwork. The following applies only to Wayland and Weston. @@ -65,60 +67,64 @@ appropriately will help maintainer work. The following patch states are found in Patchwork: - New - Patches under discussion or not yet processed. +- **New**: + Patches under discussion or not yet processed. - Under review - Mostly unused state. +- **Under review**: + Mostly unused state. - Accepted - The patch is merged in the master branch upstream, as is or slightly - modified. +- **Accepted**: + The patch is merged in the master branch upstream, as is or slightly + modified. - Rejected - The idea or approach is rejected and cannot be fixed by revising - the patch. +- **Rejected**: + The idea or approach is rejected and cannot be fixed by revising + the patch. - RFC - Request for comments, not meant to be merged as is. +- **RFC**: + Request for comments, not meant to be merged as is. - Not applicable - The email was not actually a patch, or the patch is not for Wayland or - Weston. Libinput patches are usually automatically ignored by Wayland - Patchwork, but if they get through, they will be marked as Not - applicable. +- **Not applicable**: + The email was not actually a patch, or the patch is not for Wayland or + Weston. Libinput patches are usually automatically ignored by Wayland + Patchwork, but if they get through, they will be marked as Not + applicable. - Changes requested - Reviewers determined that changes to the patch are needed. The - submitter is expected to send a revised version. (You should - not wait for your patch to be set to this state before revising, - though.) +- **Changes requested**: + Reviewers determined that changes to the patch are needed. The + submitter is expected to send a revised version. (You should + not wait for your patch to be set to this state before revising, + though.) - Awaiting upstream - Mostly unused as the patch is waiting for upstream actions but - is not shown in the default list, which means it is easy to - overlook. +- **Awaiting upstream**: + Mostly unused as the patch is waiting for upstream actions but + is not shown in the default list, which means it is easy to + overlook. - Superseded - A revised version of the patch has been submitted. +- **Superseded**: + A revised version of the patch has been submitted. - Deferred - Used mostly during freeze periods before releases, to temporarily - hide patches that cannot be merged during a freeze. +- **Deferred**: + Used mostly during freeze periods before releases, to temporarily + hide patches that cannot be merged during a freeze. -Note, that in the default listing, only patches in New or Under review are +Note, that in the default listing, only patches in *New* or *Under review* are shown. -There is also a command line interface to Patchwork called 'pwclient', see +There is also a command line interface to Patchwork called `pwclient`, see http://patchwork.freedesktop.org/project/wayland/ -for links where to get it and the sample .pwclientrc for Wayland/Weston. +for links where to get it and the sample `.pwclientrc` for Wayland/Weston. -== Coding style == +Coding style +------------ You should follow the style of the file you're editing. In general, we try to follow the rules below. +**Note: this file uses spaces due to markdown rendering issues for tabs. + Code must be implemented using tabs.** + - indent with tabs, and a tab is always 8 characters wide - opening braces are on the same line as the if statement; - no braces in an if-body with just one statement; @@ -127,23 +133,25 @@ try to follow the rules below. - there is always an empty line between variable declarations and the code; +```c static int my_function(void) { - int a = 0; + int a = 0; - if (a) - b(); - else - c(); + if (a) + b(); + else + c(); - if (a) { - b(); - c(); - } else { - d(); - } + if (a) { + b(); + c(); + } else { + d(); + } } +``` - lines should be less than 80 characters wide; - when breaking lines with functions calls, the parameters are aligned @@ -152,15 +160,17 @@ my_function(void) line would be longer we break it around the equal '=' sign if it makes sense; - long_variable_name = - function_with_a_really_long_name(parameter1, parameter2, - parameter3, parameter4); +```c + long_variable_name = + function_with_a_really_long_name(parameter1, parameter2, + parameter3, parameter4); - x = function_with_a_really_long_name(parameter1, parameter2, - parameter3, parameter4); + x = function_with_a_really_long_name(parameter1, parameter2, + parameter3, parameter4); +``` - -== Conduct == +Conduct +======= As a freedesktop.org project, Wayland follows the Contributor Covenant, found at: @@ -172,7 +182,8 @@ trackers. The community represents the project as a whole, and abusive or bullying behaviour is not tolerated by the project. -== Licensing == +Licensing +========= Wayland is licensed with the intention to be usable anywhere X.org is. Originally, X.org was covered under the MIT X11 license, but changed to @@ -185,9 +196,6 @@ in Expat. New source code files should specify the MIT Expat license in their boilerplate, as part of the copyright statement. -== References == - - [1] http://git-scm.com/documentation - - [2] http://who-t.blogspot.de/2009/12/on-commit-messages.html +[git documentation]: http://git-scm.com/documentation +[notes on commit messages]: http://who-t.blogspot.de/2009/12/on-commit-messages.html From 35d0425e39a6fa9d358ffff507c97a79fc112dc9 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 14 Jun 2018 18:14:14 +0100 Subject: [PATCH 0530/1152] .gitlab-ci.yml: collect the distcheck error logs Currently we issue both check and distcheck, as reportedly there has been cases in the past one works, while the other doesn't. Yet we only collect the check artefacts (test logs). Correct that, by picking the distcheck ones as well. Note: the build-*/wayland*/ directory is purged by distcheck if it runs successfully. Signed-off-by: Emil Velikov Reviewed-by: Pekka Paalanen --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc1a005a..24896659 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,5 +31,6 @@ build-native: when: always paths: - build-*/wayland-*.tar.xz + - build-*/wayland*/_build/sub/*.log - build-*/*.log - prefix-* From f16eae15e1862f8cf07450ab1587cb8190b7606e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 13 Jun 2018 16:02:51 +0300 Subject: [PATCH 0531/1152] contributing: add review guidelines This sets up the standards for patch review, and defines when a patch can be merged. I believe these are the practises we have been using already for a long time, now they are just written down explicitly. It's not an exhaustive list of criteria and likely cannot ever be, but it should give a good idea of what level of review we want to have. It has been written in general terms, so that we can easily apply the same text not just to Wayland, but also Weston and other projects as necessary. This addition is not redundant with https://wayland.freedesktop.org/reviewing.html . The web page is a friendly introduction and encouragement for people to get involved. The guidelines here are more specific and aimed for people who seek commit rights or maintainership. Signed-off-by: Pekka Paalanen Reviewed-by: Matheus Santana Reviewed-by: Daniel Stone Reviewed-by: Emil Velikov Reviewed-by: Derek Foreman --- CONTRIBUTING.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ad75b87..6e74b6de 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -197,5 +197,54 @@ New source code files should specify the MIT Expat license in their boilerplate, as part of the copyright statement. +Review +====== + +All patches, even trivial ones, require at least one positive review +(Reviewed-by). Additionally, if no Reviewed-by's have been given by +people with commit access, there needs to be at least one Acked-by from +someone with commit access. A person with commit access is expected to be +able to evaluate the patch with respect to the project scope and architecture. + +During review, the following matters should be checked: + +- The commit message explains why the change is being made. + +- The code fits the project's scope. + +- The code license is the same MIT licence the project generally uses. + +- Stable ABI or API is not broken. + +- Stable ABI or API additions must be justified by actual use cases, not only +by speculation. They must also be documented, and it is strongly recommended to +include tests excercising the additions in the test suite. + +- The code fits the existing software architecture, e.g. no layering +violations. + +- The code is correct and does not ignore corner-cases. + +- In a patch series, every intermediate step produces correct code as well. + +- The code does what it says in the commit message and changes nothing else. + +- The test suite passes. + +- The code does not depend on API or ABI which has no working free open source +implementation. + +- The code is not dead or untestable. E.g. if there are no free open source +software users for it then it is effectively dead code. + +- The code is written to be easy to understand, or if code cannot be clear +enough on its own there are code comments to explain it. + +- The code is minimal, i.e. prefer refactor and re-use when possible unless +clarity suffers. + +- The code adheres to the style guidelines. + + [git documentation]: http://git-scm.com/documentation [notes on commit messages]: http://who-t.blogspot.de/2009/12/on-commit-messages.html From bb1a8ca91e7d99f54b43ece01674ccbd720ec4bd Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 15 Jun 2018 17:25:07 +0300 Subject: [PATCH 0532/1152] contributing: commit rights This has been copied from https://cgit.freedesktop.org/xorg/app/intel-gpu-tools/tree/CONTRIBUTING?id=eccae1360d6d01e73c6af2bd97122cef708207ef and slightly edited to better with Wayland and Weston. The intention is to make it easier to give out commit access to new people, let them know what is expected of them, and help the community to grow. Hopefully this will in time improve the patch review throughput and timeliness. The original text was introduced in https://cgit.freedesktop.org/xorg/app/intel-gpu-tools/commit/CONTRIBUTING?id=0350f0e7f6a0e07281445fc3082aa70419f4aac7 Signed-off-by: Pekka Paalanen Reviewed-by: Matheus Santana Reviewed-by: Daniel Stone Reviewed-by: Emil Velikov Reviewed-by: Derek Foreman --- CONTRIBUTING.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e74b6de..70d0eca0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -246,5 +246,38 @@ clarity suffers. - The code adheres to the style guidelines. +Commit rights +============= + +Commit rights will be granted to anyone who requests them and fulfills the +below criteria: + +- Submitted some (10 as a rule of thumb) non-trivial (not just simple + spelling fixes and whitespace adjustment) patches that have been merged + already. + +- Are actively participating in public discussions about their work (on the + mailing list or IRC). This should not be interpreted as a requirement to + review other peoples patches but just make sure that patch submission isn't + one-way communication. Cross-review is still highly encouraged. + +- Will be regularly contributing further patches. This includes regular + contributors to other parts of the open source graphics stack who only + do the occasional development in this project. + +- Agrees to use their commit rights in accordance with the documented merge + criteria, tools, and processes. + +To apply for commit rights, create a new issue in gitlab for the respective +project and give it the "accounts" label. + +Committers are encouraged to request their commit rights get removed when they +no longer contribute to the project. Commit rights will be reinstated when they +come back to the project. + +Maintainers and committers should encourage contributors to request commit +rights, especially junior contributors tend to underestimate their skills. + + [git documentation]: http://git-scm.com/documentation [notes on commit messages]: http://who-t.blogspot.de/2009/12/on-commit-messages.html From a9ff9cc7d591124413249a4d803188cd3f9165ca Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 18 Jun 2018 06:58:46 -0400 Subject: [PATCH 0533/1152] doc: update IANA MIME types registry URL Use a more official one, served over HTTP rather than FTP. Reviewed-by: Matheus Santana Acked-by: Pekka Paalanen --- doc/publican/sources/Protocol.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 9fdee9a7..fedaaaba 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -479,7 +479,7 @@
MIME is defined in RFC's 2045-2049. A - + registry of MIME types is maintained by the Internet Assigned Numbers Authority (IANA). From 7cbaa871cccf0e07123185d5db8a35f7eee27f37 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 15 Feb 2018 13:48:35 +0200 Subject: [PATCH 0534/1152] client: remove definition of wl_global Nothing on the client side uses it since 9fe75537ad207c1496e6d9be41a8f5af4b876506 which was just before the 0.99 release. Signed-off-by: Pekka Paalanen Reviewed-By: Markus Ongyerth --- src/wayland-client.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index efeb7450..0ccfc660 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -71,13 +71,6 @@ struct wl_proxy { uint32_t version; }; -struct wl_global { - uint32_t id; - char *interface; - uint32_t version; - struct wl_list link; -}; - struct wl_event_queue { struct wl_list event_list; struct wl_display *display; From b5f97895da4aae4ba87ae3aa7da36abb86dcb58c Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 3 Jul 2018 13:32:00 +0300 Subject: [PATCH 0535/1152] contributing: how to read the review rules This is to avoid fighting around the letter of the guidelines. This is not a protocol spec. Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone Reviewed-by: Derek Foreman --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 70d0eca0..538613fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,6 +206,11 @@ people with commit access, there needs to be at least one Acked-by from someone with commit access. A person with commit access is expected to be able to evaluate the patch with respect to the project scope and architecture. +The below review guidelines are intended to be interpreted in spirit, not by +the letter. There may be circumstances where some guidelines are better +ignored. We rely very much on the judgement of reviewers and commit rights +holders. + During review, the following matters should be checked: - The commit message explains why the change is being made. From 3cfdd56af4444fce71d4ae8c8e515cec8eafb3e2 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 3 Jul 2018 13:32:01 +0300 Subject: [PATCH 0536/1152] contributing: review rules for bugs Half of the ideas came from Daniel but most of them are reworded, the rest are my thoughts. Mention compiler warnings specifically, and be more explicit on what kind of code or bugs or bug fixes are acceptable or not. Clarify commit scope. v2: move the "In a patch series" rule to the bottom, reworded. Cc: Daniel Stone Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone Reviewed-by: Derek Foreman --- CONTRIBUTING.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 538613fc..cbe02a37 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -228,11 +228,21 @@ include tests excercising the additions in the test suite. - The code fits the existing software architecture, e.g. no layering violations. -- The code is correct and does not ignore corner-cases. +- The code is correct and does not introduce new failures for existing users, +does not add new corner-case bugs, and does not introduce new compiler +warnings. -- In a patch series, every intermediate step produces correct code as well. +- The patch does what it says in the commit message and changes nothing else. -- The code does what it says in the commit message and changes nothing else. +- The patch is a single logical change. If the commit message addresses +multiple points, it is a hint that the commit might need splitting up. + +- A bug fix should target the underlying root cause instead of hiding symptoms. +If a complete fix is not practical, partial fixes are acceptable if they come +with code comments and filed Gitlab issues for the remaining bugs. + +- The bug root cause rule applies to external software components as well, e.g. +do not work around kernel driver issues in userspace. - The test suite passes. @@ -250,6 +260,8 @@ clarity suffers. - The code adheres to the style guidelines. +- In a patch series, every intermediate step adheres to the above guidelines. + Commit rights ============= From 9f80af930b76139fdb851708d70fa26ddf3ed09e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 3 Jul 2018 13:32:02 +0300 Subject: [PATCH 0537/1152] contributing: about re-sending patches This is what is generally expected from people who re-send patches, whether the patches are their own or not. Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone Reviewed-by: Derek Foreman --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cbe02a37..9442d75e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,14 @@ responsibility for the copyright status of the code. We won't reject patches that lack S-o-b, but it is strongly recommended. +When you re-send patches, revised or not, it would be very good to document the +changes compared to the previous revision in the commit message and/or the +cover letter. If you have already received Reviewed-by or Acked-by tags, you +should evaluate whether they still apply and include them in the respective +commit messages. Otherwise the tags may be lost, reviewers miss the credit they +deserve, and the patches may cause redundant review effort. + + Tracking patches and following up --------------------------------- From 14705824a61155a9b2366c1d982832f8c5a8366b Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 3 Jul 2018 13:32:03 +0300 Subject: [PATCH 0538/1152] contributing: document the release cycle freezes These should be the conventions we have been using since 1.0, written down more accurately. Signed-off-by: Pekka Paalanen Reviewed-by: Daniel Stone Reviewed-by: Derek Foreman --- CONTRIBUTING.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9442d75e..4273d99d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -304,5 +304,40 @@ Maintainers and committers should encourage contributors to request commit rights, especially junior contributors tend to underestimate their skills. +Stabilising for releases +======================== + +A release cycle ends with a stable release which also starts a new cycle and +lifts any code freezes. Gradual code freezing towards a stable release starts +with an alpha release. The release stages of a cycle are: + +- **Alpha release**: + Signified by version number #.#.91. + Major features must have landed before this. Major features include + invasive code motion and refactoring, high risk changes, and new stable + library ABI. + +- **Beta release**: + Signified by version number #.#.92. + Minor features must have landed before this. Minor features include all + new features that are not major, low risk changes, clean-ups, and + documentation. Stable ABI that was new in the alpha release can be removed + before a beta release if necessary. + +- **Release candidates (RC)**: + Signified by version number #.#.93 and up to #.#.99. + Bug fixes that are not release critical must have landed before this. + Release critical bug fixes can still be landed after this, but they may + call for another RC. + +- **Stable release**: + Signified by version number #.#.0. + Ideally no changes since the last RC. + +Mind that version #.#.90 is never released. It is used during development when +no code freeze is in effect. Stable branches and point releases are not covered +by the above. + + [git documentation]: http://git-scm.com/documentation [notes on commit messages]: http://who-t.blogspot.de/2009/12/on-commit-messages.html From 4cc1c1519a7001d1f9e4db8c9dea6fa191b88744 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 13 Jul 2018 11:27:03 -0500 Subject: [PATCH 0539/1152] configure.ac: bump to version 1.15.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d0a10e17..81cf4077 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [15]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 504db9d8e5d3a6de4abbbb0ae11a82fd81b3771f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Jul 2018 07:27:05 -0400 Subject: [PATCH 0540/1152] protocol: allow to send a zero physical output size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Physical size doesn't always make sense for all outputs. In case it's not available or not relevant, allow compositors to send zero. Acked-by: Daniel Stone Acked-by: Jonas Ådahl Acked-by: Olivier Fourdan --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index b5662e02..141038b7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2399,6 +2399,9 @@ The geometry event describes geometric properties of the output. The event is sent when binding to the output object and whenever any of the properties change. + + The physical size can be set to zero if it doesn't make sense for this + output (e.g. for projectors or virtual outputs). From e614d79b6534541c3c1d2e0000c90f74e62622fc Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 16 Feb 2018 10:54:40 -0600 Subject: [PATCH 0541/1152] wayland-server: Finally remove deprecated struct wl_buffer definition commit d94a8722cb29d8b897672be66ff3c9ff79eab6fe warned this was coming, back in 2013. I've seen libraries that have wayland client and server using functions in the same file. Since struct wl_buffer still exists as an opaque entity in client code, the vestigial deprecated wl_buffer from the server include will generate warnings when not building with WL_HIDE_DEPRECATED. Signed-off-by: Derek Foreman Acked-by: Emil Velikov Reviewed-by: Pekka Paalanen Reviewed-by: Daniel Stone --- src/wayland-server.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/wayland-server.h b/src/wayland-server.h index ccf9783a..1be565f2 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -70,12 +70,6 @@ struct wl_resource { void *data; }; -struct wl_buffer { - struct wl_resource resource; - int32_t width, height; - uint32_t busy_count; -} WL_DEPRECATED; - uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource) WL_DEPRECATED; From 99c3c10ad0e0a27a8c5d33d1e285e8b77fe0534b Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Sat, 21 Jul 2018 11:58:41 +0100 Subject: [PATCH 0542/1152] build: Remove execinfo.h check The check for the execinfo.h header is only advisory; the build will not fail if it is not present, and set HAVE_EXECINFO_H if it is. The check was added in commit bc3e020475e ("build: Add declaration checks to check for required syscall flags") with no obvious use or reasoning. Remove the no-op check. Signed-off-by: Daniel Stone Reviewed-by: Derek Foreman Reviewed-by: Emil Velikov --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 81cf4077..8c2fb822 100644 --- a/configure.ac +++ b/configure.ac @@ -109,7 +109,6 @@ if test "x$enable_libraries" = "xyes"; then AC_CHECK_DECL(CLOCK_MONOTONIC,[], [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland libraries")], [[#include ]]) - AC_CHECK_HEADERS([execinfo.h]) fi PKG_CHECK_MODULES(EXPAT, [expat], [], From bd56f9e29f16ca956b3e4d9658e32f1125db9d2d Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Sat, 21 Jul 2018 12:04:13 +0100 Subject: [PATCH 0543/1152] build: Remove support for non-pkg-config Expat The Expat XML library has shipped a pkg-config file for long enough to be in Debian's oldstable (Jessie, April 2015) and Ubuntu's oldest supported LTS (Trusty, 14.04). The pkg-config file was added in Expat upstream's commit 352cfc8f59a7, in September 2007. Drop build support for versions of Expat which do not ship a pkg-config file. Signed-off-by: Daniel Stone Reviewed-by: Derek Foreman Reviewed-by: Emil Velikov --- configure.ac | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 8c2fb822..0022dcda 100644 --- a/configure.ac +++ b/configure.ac @@ -111,16 +111,7 @@ if test "x$enable_libraries" = "xyes"; then [[#include ]]) fi -PKG_CHECK_MODULES(EXPAT, [expat], [], - [AC_CHECK_HEADERS(expat.h, [], - [AC_MSG_ERROR([Can't find expat.h. Please install expat.])]) - SAVE_LIBS="$LIBS" - AC_SEARCH_LIBS(XML_ParserCreate, expat, [], - [AC_MSG_ERROR([Can't find expat library. Please install expat.])]) - EXPAT_LIBS="$LIBS" - LIBS="$SAVE_LIBS" - AC_SUBST(EXPAT_LIBS) - ]) +PKG_CHECK_MODULES(EXPAT, [expat]) AM_CONDITIONAL([DTD_VALIDATION], [test "x$enable_dtd_validation" = "xyes"]) if test "x$enable_dtd_validation" = "xyes"; then From 614c137200a4f62658ea9144193661f7c5f38c1d Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Sun, 22 Jul 2018 10:17:39 +0100 Subject: [PATCH 0544/1152] spec: Delete old unused directory The protocol spec used to live here, but it's now part of the regular doc build. The PNG files are created as part of the doc build. Delete the pre-generated versions. Signed-off-by: Daniel Stone Reviewed-by: Derek Foreman --- spec/.gitignore | 3 --- spec/wayland-architecture.png | Bin 29162 -> 0 bytes spec/x-architecture.png | Bin 37306 -> 0 bytes 3 files changed, 3 deletions(-) delete mode 100644 spec/.gitignore delete mode 100644 spec/wayland-architecture.png delete mode 100644 spec/x-architecture.png diff --git a/spec/.gitignore b/spec/.gitignore deleted file mode 100644 index 4962683d..00000000 --- a/spec/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -main.aux -main.log -main.pdf diff --git a/spec/wayland-architecture.png b/spec/wayland-architecture.png deleted file mode 100644 index 4f92e0fb93825a68095b75d499bac00e968419e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29162 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 diff --git a/spec/x-architecture.png b/spec/x-architecture.png deleted file mode 100644 index 098205b57a973311c22c914073fe53414f4c0a35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37306 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 Date: Fri, 27 Jul 2018 11:46:27 -0500 Subject: [PATCH 0545/1152] configure.ac: bump to version 1.15.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0022dcda..2be77edc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [15]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 1e4af929d2be8e1fd277100558a0ecc44e3fe6ed Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 6 Aug 2018 11:49:31 +0100 Subject: [PATCH 0546/1152] contributing: Weston now uses GitLab MRs Note that Weston uses GitLab MRs for review, not mail. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen --- CONTRIBUTING.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4273d99d..686ed63f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,12 +55,16 @@ Tracking patches and following up --------------------------------- [Wayland Patchwork](http://patchwork.freedesktop.org/project/wayland/list/) is -used for tracking patches to Wayland and Weston. Xwayland patches are tracked -with the [Xorg project](https://patchwork.freedesktop.org/project/Xorg/list/) -instead. Libinput patches, even though they use the same mailing list as +used for tracking patches to Wayland. Xwayland patches are tracked with the +[Xorg project](https://patchwork.freedesktop.org/project/Xorg/list/) +instead. Weston uses +[GitLab merge requests](https://gitlab.freedesktop.org/wayland/weston/merge_requests) +for code review, and does not use mailing list review at all. + +Libinput patches, even though they use the same mailing list as Wayland, are not tracked in the Wayland Patchwork. -The following applies only to Wayland and Weston. +The following applies only to Wayland. If a patch is not found in Patchwork, there is a high possibility for it to be forgotten. Patches attached to bug reports or not arriving to the mailing list @@ -93,8 +97,8 @@ The following patch states are found in Patchwork: Request for comments, not meant to be merged as is. - **Not applicable**: - The email was not actually a patch, or the patch is not for Wayland or - Weston. Libinput patches are usually automatically ignored by Wayland + The email was not actually a patch, or the patch is not for Wayland. + Libinput patches are usually automatically ignored by Wayland Patchwork, but if they get through, they will be marked as Not applicable. @@ -121,7 +125,7 @@ shown. There is also a command line interface to Patchwork called `pwclient`, see http://patchwork.freedesktop.org/project/wayland/ -for links where to get it and the sample `.pwclientrc` for Wayland/Weston. +for links where to get it and the sample `.pwclientrc` for Wayland. Coding style From fde60465c3b30c9bbcfdd67622ce5539709bac40 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 10 Aug 2018 13:01:10 -0500 Subject: [PATCH 0547/1152] configure.ac: bump to version 1.15.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2be77edc..9419ae36 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [15]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From f5b9e3b9a1df83ec3a6d219d7c28a1ac5bc0f339 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Tue, 14 Aug 2018 13:07:52 +0200 Subject: [PATCH 0548/1152] connection: Prevent integer overflow in DIV_ROUNDUP. The DIV_ROUNDUP macro would overflow when trying to round values higher than MAX_UINT32 - (a - 1). The result is 0 after the division. This is potential security issue when demarshalling an array because the length check is performed with the overflowed value, but then the original huge value is stored for later use. The issue was present only on 32bit platforms. The use of size_t in the DIV_ROUNDUP macro already promoted everything to 64 bit size on 64 bit systems. Reviewed-by: Pekka Paalanen Reviewed-by: Derek Foreman Style changes by Derek Foreman --- src/connection.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/connection.c b/src/connection.c index 294c521a..cb4b8d5d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -44,7 +44,15 @@ #include "wayland-private.h" #include "wayland-os.h" -#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) ) +static inline uint32_t +div_roundup(uint32_t n, size_t a) +{ + /* The cast to uint64_t is necessary to prevent overflow when rounding + * values close to UINT32_MAX. After the division it is again safe to + * cast back to uint32_t. + */ + return (uint32_t) (((uint64_t) n + (a - 1)) / a); +} struct wl_buffer { char data[4096]; @@ -734,7 +742,7 @@ wl_connection_demarshal(struct wl_connection *connection, break; } - next = p + DIV_ROUNDUP(length, sizeof *p); + next = p + div_roundup(length, sizeof *p); if (next > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", @@ -793,7 +801,7 @@ wl_connection_demarshal(struct wl_connection *connection, case 'a': length = *p++; - next = p + DIV_ROUNDUP(length, sizeof *p); + next = p + div_roundup(length, sizeof *p); if (next > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", @@ -1068,7 +1076,7 @@ buffer_size_for_closure(struct wl_closure *closure) } size = strlen(closure->args[i].s) + 1; - buffer_size += 1 + DIV_ROUNDUP(size, sizeof(uint32_t)); + buffer_size += 1 + div_roundup(size, sizeof(uint32_t)); break; case 'a': if (closure->args[i].a == NULL) { @@ -1077,7 +1085,7 @@ buffer_size_for_closure(struct wl_closure *closure) } size = closure->args[i].a->size; - buffer_size += (1 + DIV_ROUNDUP(size, sizeof(uint32_t))); + buffer_size += (1 + div_roundup(size, sizeof(uint32_t))); break; default: break; @@ -1139,11 +1147,11 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, size = strlen(closure->args[i].s) + 1; *p++ = size; - if (p + DIV_ROUNDUP(size, sizeof *p) > end) + if (p + div_roundup(size, sizeof *p) > end) goto overflow; memcpy(p, closure->args[i].s, size); - p += DIV_ROUNDUP(size, sizeof *p); + p += div_roundup(size, sizeof *p); break; case 'a': if (closure->args[i].a == NULL) { @@ -1154,11 +1162,11 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, size = closure->args[i].a->size; *p++ = size; - if (p + DIV_ROUNDUP(size, sizeof *p) > end) + if (p + div_roundup(size, sizeof *p) > end) goto overflow; memcpy(p, closure->args[i].a->data, size); - p += DIV_ROUNDUP(size, sizeof *p); + p += div_roundup(size, sizeof *p); break; default: break; From f7fdface41a9205c12aedf7fe04aba7792402909 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Tue, 14 Aug 2018 13:07:53 +0200 Subject: [PATCH 0549/1152] connection: Prevent pointer overflow from large lengths. If the remote side sends sufficiently large `length` field, it will overflow the `p` pointer. Technically it is undefined behavior, in practice it makes `p < end`, so the length check passes. Attempts to access the data later causes crashes. This issue manifests only on 32bit systems, but the behavior is undefined everywhere. Reviewed-by: Pekka Paalanen Reviewed-by: Derek Foreman --- src/connection.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/connection.c b/src/connection.c index cb4b8d5d..f9652107 100644 --- a/src/connection.c +++ b/src/connection.c @@ -686,7 +686,7 @@ wl_connection_demarshal(struct wl_connection *connection, struct wl_map *objects, const struct wl_message *message) { - uint32_t *p, *next, *end, length, id; + uint32_t *p, *next, *end, length, length_in_u32, id; int fd; char *s; int i, count, num_arrays; @@ -742,8 +742,8 @@ wl_connection_demarshal(struct wl_connection *connection, break; } - next = p + div_roundup(length, sizeof *p); - if (next > end) { + length_in_u32 = div_roundup(length, sizeof *p); + if ((uint32_t) (end - p) < length_in_u32) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, @@ -751,6 +751,7 @@ wl_connection_demarshal(struct wl_connection *connection, errno = EINVAL; goto err; } + next = p + length_in_u32; s = (char *) p; @@ -801,8 +802,8 @@ wl_connection_demarshal(struct wl_connection *connection, case 'a': length = *p++; - next = p + div_roundup(length, sizeof *p); - if (next > end) { + length_in_u32 = div_roundup(length, sizeof *p); + if ((uint32_t) (end - p) < length_in_u32) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, @@ -810,6 +811,7 @@ wl_connection_demarshal(struct wl_connection *connection, errno = EINVAL; goto err; } + next = p + length_in_u32; array_extra->size = length; array_extra->alloc = 0; From de3079685c320ac290bb1c5728db27e3bc829c90 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 17 Aug 2018 11:19:45 -0500 Subject: [PATCH 0550/1152] configure.ac: bump to version 1.15.94 for the RC2 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9419ae36..c6354ff0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [15]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_micro_version], [94]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 581c62841f2215ee12a8d9af4e4c05d052c6a204 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Tue, 21 Aug 2018 10:47:29 +0200 Subject: [PATCH 0551/1152] tests: Demarshalling of very long array/string lengths. Attempting to demarshal message with array or string longer than its body should return failure. Handling the length correctly is tricky when it gets to near-UINT32_MAX values. Unexpected overflows can cause crashes and other security issues. These tests verify that demarshalling such message gives failure instead of crash. v2: Added consts, serialized opcode and size properly, updated style. Reviewed-by: Pekka Paalanen Acked-by: Derek Foreman --- tests/connection-test.c | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/connection-test.c b/tests/connection-test.c index 157e1bc9..018e2ac0 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -533,6 +533,69 @@ TEST(connection_marshal_demarshal) release_marshal_data(&data); } +static void +expected_fail_demarshal(struct marshal_data *data, const char *format, + const uint32_t *msg, int expected_error) +{ + struct wl_message message = { "test", format, NULL }; + struct wl_closure *closure; + struct wl_map objects; + int size = (msg[1] >> 16); + + assert(write(data->s[1], msg, size) == size); + assert(wl_connection_read(data->read_connection) == size); + + wl_map_init(&objects, WL_MAP_SERVER_SIDE); + closure = wl_connection_demarshal(data->read_connection, + size, &objects, &message); + + assert(closure == NULL); + assert(errno == expected_error); +} + +/* These tests are verifying that the demarshaling code will gracefuly handle + * clients lying about string and array lengths and giving values near + * UINT32_MAX. Before fixes f7fdface and f5b9e3b9 this test would crash on + * 32bit systems. + */ +TEST(connection_demarshal_failures) +{ + struct marshal_data data; + unsigned int i; + uint32_t msg[3]; + + const uint32_t overflowing_values[] = { + /* Values very close to UINT32_MAX. Before f5b9e3b9 these + * would cause integer overflow in DIV_ROUNDUP. */ + 0xffffffff, 0xfffffffe, 0xfffffffd, 0xfffffffc, + + /* Values at various offsets from UINT32_MAX. Before f7fdface + * these would overflow the "p" pointer on 32bit systems, + * effectively subtracting the offset from it. It had good + * chance to cause crash depending on what was stored at that + * offset before "p". */ + 0xfffff000, 0xffffd000, 0xffffc000, 0xffffb000 + }; + + setup_marshal_data(&data); + + /* sender_id, does not matter */ + msg[0] = 0; + + /* (size << 16 | opcode), opcode is 0, does not matter */ + msg[1] = sizeof(msg) << 16; + + for (i = 0; i < ARRAY_LENGTH(overflowing_values); i++) { + /* length of the string or array */ + msg[2] = overflowing_values[i]; + + expected_fail_demarshal(&data, "s", msg, EINVAL); + expected_fail_demarshal(&data, "a", msg, EINVAL); + } + + release_marshal_data(&data); +} + TEST(connection_marshal_alot) { struct marshal_data data; From 254bef7b4a32b52346bdcdf4b8a432b582a9ddb4 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 24 Aug 2018 12:39:14 -0500 Subject: [PATCH 0552/1152] configure.ac: bump to version 1.16.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c6354ff0..f05fba48 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [15]) -m4_define([wayland_micro_version], [94]) +m4_define([wayland_minor_version], [16]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From f1d10fb6092c772a7c5ac192890a8d2bbe695a5f Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 24 Aug 2018 13:41:14 -0500 Subject: [PATCH 0553/1152] configure.ac: Reopen master for regular development --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f05fba48..18fb6492 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [16]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From a2ed67e85c386413979ab30bf5ec48dc19fcf99e Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Fri, 24 Aug 2018 16:32:42 +0100 Subject: [PATCH 0554/1152] scanner: Plug two memory leaks Found with both ASan leak sanitizer and Valgrind. We were trivially leaking the enum name for every arg parsed by the scanner which had one. If libxml-based DTD validation was enabled, we would also leak the DTD itself, despite diligently freeing the document, context, etc. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Reviewed-by: Peter Hutterer --- src/scanner.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index 205c28a9..3afc3d3d 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -133,6 +133,7 @@ is_dtd_valid(FILE *input, const char *filename) rc = xmlValidateDtd(dtdctx, doc, dtd); xmlFreeDoc(doc); xmlFreeParserCtxt(ctx); + xmlFreeDtd(dtd); xmlFreeValidCtxt(dtdctx); /* xmlIOParseDTD consumes buffer */ @@ -432,6 +433,7 @@ free_arg(struct arg *arg) free(arg->name); free(arg->interface_name); free(arg->summary); + free(arg->enumeration_name); free(arg); } From 5fab243a729c949d38463c47040ea6abec8d7850 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 27 Aug 2018 22:26:37 +0100 Subject: [PATCH 0555/1152] scanner: Mark fail() as noreturn Help static analysers by letting them know that once we fail(), execution will terminally complete. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Reviewed-by: Peter Hutterer --- src/scanner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 3afc3d3d..084f196d 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -371,7 +371,7 @@ desc_dump(char *desc, const char *fmt, ...) putchar('\n'); } -static void +static void __attribute__ ((noreturn)) fail(struct location *loc, const char *msg, ...) { va_list ap; From 4939923d3a8487f6644b1feb657693d8f929297b Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 28 Aug 2018 23:59:35 +0100 Subject: [PATCH 0556/1152] scanner: Reverse expat/libxml include order libxml2 unconditonally defines XMLCALL to nothing. Expat does not redefine XMLCALL if it is already defined, but if it is not, and we are building with gcc on i386 (not x86-64), it will define it as 'cdecl'. Including Expat before libxml thus results in a warning about XMLCALL being redefined. Luckily we can get around this by just reversing the include order: cdecl is a no-op on Unix-like systems, so by having libxml first define XMLCALL to nothing and including Expat afterwards, we avoid the warning and lose nothing. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Reviewed-by: Peter Hutterer --- src/scanner.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 084f196d..a94be5d7 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,10 @@ extern char DTD_DATA_begin; extern int DTD_DATA_len; #endif +/* Expat must be included after libxml as both want to declare XMLCALL; see + * the Git commit that 'git blame' for this comment points to for more. */ +#include + #include "wayland-util.h" #define PROGRAM_NAME "wayland-scanner" From 9575d1c772378df73cd421997b70d4a880575911 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Fri, 24 Aug 2018 16:48:13 +0100 Subject: [PATCH 0557/1152] tests: Use volatile pointer for NULL dereference Clang warns that it can silently discard a non-volatile write to a NULL pointer (perhaps it constitutes undefined behaviour?), and recommends changing it to volatile. This patch slavishly complies with the demand of the unfeeling machine. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Reviewed-by: Peter Hutterer --- tests/sanity-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 66ca16fb..2495a115 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -70,8 +70,10 @@ FAIL_TEST(fail_kill) FAIL_TEST(fail_segv) { + char * volatile *null = 0; + test_disable_coredumps(); - * (char **) 0 = "Goodbye, world"; + *null = "Goodbye, world"; } FAIL_TEST(sanity_assert) From cb9a2557e11f294256943f5b4187940d7234820c Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Fri, 24 Aug 2018 16:53:25 +0100 Subject: [PATCH 0558/1152] tests: Overly elaborate compiler warning workaround Clang will rightly point out that example_sockaddr_un in socket-test will get discarded from the compilation unit as it is completely unused. Put in a couple of lines which of no value other than stopping Clang from complaining. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Reviewed-by: Peter Hutterer --- tests/socket-test.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/socket-test.c b/tests/socket-test.c index e9705628..8d39edce 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -42,7 +42,7 @@ * See `man 7 unix`. */ -static const struct sockaddr_un example_sockaddr_un; +static struct sockaddr_un example_sockaddr_un; #define TOO_LONG (1 + sizeof example_sockaddr_un.sun_path) @@ -69,6 +69,11 @@ TEST(socket_path_overflow_client_connect) d = wl_display_connect(path); assert(d == NULL); assert(errno == ENAMETOOLONG); + + /* This is useless, but prevents a warning about example_sockaddr_un + * being discarded from the compilation unit. */ + strcpy(example_sockaddr_un.sun_path, "happy now clang?"); + assert(example_sockaddr_un.sun_path[0] != '\0'); } TEST(socket_path_overflow_server_create) From 01095a9ce4d8457ee2f221848b9805c4b5cffc95 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Fri, 24 Aug 2018 16:15:59 +0100 Subject: [PATCH 0559/1152] tests: Remove memory leak checking infrastructure There are far better ways to detect memory leaks, such as either valgrind or ASan. Having Meson makes it really easy to use these tools in our tests, and we can do that in CI as well. Having these local wrappers actually completely broke ASan usage, so remove them in favour of using the more powerful options. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Reviewed-by: Peter Hutterer --- tests/sanity-test.c | 66 ++-------------------------------- tests/test-compositor.c | 5 ++- tests/test-runner.c | 79 ++++++----------------------------------- tests/test-runner.h | 13 +++---- 4 files changed, 20 insertions(+), 143 deletions(-) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 2495a115..98beca8d 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -35,7 +35,7 @@ #include "test-compositor.h" -extern int leak_check_enabled; +extern int fd_leak_check_enabled; TEST(empty) { @@ -83,71 +83,11 @@ FAIL_TEST(sanity_assert) assert(0); } -FAIL_TEST(sanity_malloc_direct) -{ - void *p; - - assert(leak_check_enabled); - - p = malloc(10); /* memory leak */ - assert(p); /* assert that we got memory, also prevents - * the malloc from getting optimized away. */ - free(NULL); /* NULL must not be counted */ - test_disable_coredumps(); -} - -TEST(disable_leak_checks) -{ - volatile void *mem; - assert(leak_check_enabled); - /* normally this should be on the beginning of the test. - * Here we need to be sure, that the leak checks are - * turned on */ - DISABLE_LEAK_CHECKS; - - mem = malloc(16); - assert(mem); -} - -FAIL_TEST(sanity_malloc_indirect) -{ - struct wl_array array; - - assert(leak_check_enabled); - - wl_array_init(&array); - - /* call into library that calls malloc */ - wl_array_add(&array, 14); - - /* not freeing array, must leak */ - - test_disable_coredumps(); -} - -FAIL_TEST(tc_client_memory_leaks) -{ - struct display *d = display_create(); - client_create_noarg(d, sanity_malloc_direct); - display_run(d); - test_disable_coredumps(); - display_destroy(d); -} - -FAIL_TEST(tc_client_memory_leaks2) -{ - struct display *d = display_create(); - client_create_noarg(d, sanity_malloc_indirect); - display_run(d); - test_disable_coredumps(); - display_destroy(d); -} - FAIL_TEST(sanity_fd_leak) { int fd[2]; - assert(leak_check_enabled); + assert(fd_leak_check_enabled); /* leak 2 file descriptors */ if (pipe(fd) < 0) @@ -185,7 +125,7 @@ sanity_fd_no_leak(void) { int fd[2]; - assert(leak_check_enabled); + assert(fd_leak_check_enabled); /* leak 2 file descriptors */ if (pipe(fd) < 0) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 0631f614..72f63515 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -156,7 +156,7 @@ run_client(void (*client_main)(void *data), void *data, int wayland_sock, int client_pipe) { char s[8]; - int cur_alloc, cur_fds; + int cur_fds; int can_continue = 0; /* Wait until display signals that client can continue */ @@ -169,7 +169,6 @@ run_client(void (*client_main)(void *data), void *data, snprintf(s, sizeof s, "%d", wayland_sock); setenv("WAYLAND_SOCKET", s, 0); - cur_alloc = get_current_alloc_num(); cur_fds = count_open_fds(); client_main(data); @@ -182,7 +181,7 @@ run_client(void (*client_main)(void *data), void *data, if (!getenv("WAYLAND_SOCKET")) cur_fds--; - check_leaks(cur_alloc, cur_fds); + check_fd_leaks(cur_fds); } static struct client_info * diff --git a/tests/test-runner.c b/tests/test-runner.c index 82a0a7b8..1487dc48 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -44,16 +44,10 @@ #include "test-runner.h" -static int num_alloc; -static void* (*sys_malloc)(size_t); -static void (*sys_free)(void*); -static void* (*sys_realloc)(void*, size_t); -static void* (*sys_calloc)(size_t, size_t); - -/* when set to 1, check if tests are not leaking memory and opened files. +/* when set to 1, check if tests are not leaking opened files. * It is turned on by default. It can be turned off by * WAYLAND_TEST_NO_LEAK_CHECK environment variable. */ -int leak_check_enabled; +int fd_leak_check_enabled; /* when this var is set to 0, every call to test_set_timeout() is * suppressed - handy when debugging the test. Can be set by @@ -65,40 +59,6 @@ static int is_atty = 0; extern const struct test __start_test_section, __stop_test_section; -__attribute__ ((visibility("default"))) void * -malloc(size_t size) -{ - num_alloc++; - return sys_malloc(size); -} - -__attribute__ ((visibility("default"))) void -free(void* mem) -{ - if (mem != NULL) - num_alloc--; - sys_free(mem); -} - -__attribute__ ((visibility("default"))) void * -realloc(void* mem, size_t size) -{ - if (mem == NULL) - num_alloc++; - return sys_realloc(mem, size); -} - -__attribute__ ((visibility("default"))) void * -calloc(size_t nmemb, size_t size) -{ - if (sys_calloc == NULL) - return NULL; - - num_alloc++; - - return sys_calloc(nmemb, size); -} - static const struct test * find_test(const char *name) { @@ -156,25 +116,12 @@ sigalrm_handler(int signum) abort(); } -int -get_current_alloc_num(void) -{ - return num_alloc; -} - void -check_leaks(int supposed_alloc, int supposed_fds) +check_fd_leaks(int supposed_fds) { int num_fds; - if (leak_check_enabled) { - if (supposed_alloc != num_alloc) { - fprintf(stderr, "Memory leak detected in test. " - "Allocated %d blocks, unfreed %d\n", num_alloc, - num_alloc - supposed_alloc); - abort(); - } - + if (fd_leak_check_enabled) { num_fds = count_open_fds(); if (supposed_fds != num_fds) { fprintf(stderr, "fd leak detected in test. " @@ -183,14 +130,14 @@ check_leaks(int supposed_alloc, int supposed_fds) abort(); } } else { - fprintf(stderr, "Leak checks disabled\n"); + fprintf(stderr, "FD leak checks disabled\n"); } } static void run_test(const struct test *t) { - int cur_alloc, cur_fds; + int cur_fds; struct sigaction sa; if (timeouts_enabled) { @@ -200,7 +147,7 @@ run_test(const struct test *t) assert(sigaction(SIGALRM, &sa, NULL) == 0); } - cur_alloc = get_current_alloc_num(); + //cur_alloc = get_current_alloc_num(); cur_fds = count_open_fds(); t->run(); @@ -209,7 +156,7 @@ run_test(const struct test *t) if (timeouts_enabled) alarm(0); - check_leaks(cur_alloc, cur_fds); + check_fd_leaks(cur_fds); exit(EXIT_SUCCESS); } @@ -348,20 +295,14 @@ int main(int argc, char *argv[]) int total, pass; siginfo_t info; - /* Load system malloc, free, and realloc */ - sys_calloc = dlsym(RTLD_NEXT, "calloc"); - sys_realloc = dlsym(RTLD_NEXT, "realloc"); - sys_malloc = dlsym(RTLD_NEXT, "malloc"); - sys_free = dlsym(RTLD_NEXT, "free"); - if (isatty(fileno(stderr))) is_atty = 1; if (is_debugger_attached()) { - leak_check_enabled = 0; + fd_leak_check_enabled = 0; timeouts_enabled = 0; } else { - leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); + fd_leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS"); } diff --git a/tests/test-runner.h b/tests/test-runner.h index 9c47a2b0..d0734009 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -63,11 +63,8 @@ count_open_fds(void); void exec_fd_leak_check(int nr_expected_fds); /* never returns */ -int -get_current_alloc_num(void); - void -check_leaks(int supposed_allocs, int supposed_fds); +check_fd_leaks(int supposed_fds); /* * set/reset the timeout in seconds. The timeout starts @@ -89,10 +86,10 @@ test_sleep(unsigned int); void test_disable_coredumps(void); -#define DISABLE_LEAK_CHECKS \ - do { \ - extern int leak_check_enabled; \ - leak_check_enabled = 0; \ +#define DISABLE_LEAK_CHECKS \ + do { \ + extern int fd_leak_check_enabled; \ + fd_leak_check_enabled = 0; \ } while (0); #endif From 905c0a341ddf0a885811d19e2b79c65a3f1d210c Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 1 Nov 2018 11:15:46 -0500 Subject: [PATCH 0560/1152] protocol: Bump seat to version 7 and require keymaps be private Weston commit 76829fc4eaea329d2a525c3978271e13bd76c078 (and similar commits for other compositors) protects the compositor's keyboard mapping from client damage by duplicating the keymap for every client. On some systems there are other potential fixes for this - such as using sealed memfds on linux - but we can't use them since essentially all client code anywhere has mapped the keyboard map with a MAP_SHARED mmap() call. While we can't break years worth of code, we can require any future clients to use MAP_PRIVATE if they use a seat version above 6. If a compositor can't use sealing or a similar facility, it should still protect itself with copied keymaps, but clients must always assume shared mapping of a keymap will fail. Signed-off-by: Derek Foreman Reviewed-by: Simon Ser Reviewed-by: Daniel Stone Reviewed-by: Philipp Kerling Acked-by: Pekka Paalanen --- protocol/wayland.xml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 141038b7..802d4331 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1660,7 +1660,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -1769,7 +1769,7 @@ - + The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -2092,7 +2092,7 @@ - + The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -2113,6 +2113,9 @@ This event provides a file descriptor to the client which can be memory-mapped to provide a keyboard mapping description. + + From version 7 onwards, the fd must be mapped with MAP_PRIVATE by + the recipient, as MAP_SHARED may fail. @@ -2203,7 +2206,7 @@ - + The wl_touch interface represents a touchscreen associated with a seat. From 921d0548035673a1bf6aeb9396b9bc728133411e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Nov 2018 13:57:00 +0000 Subject: [PATCH 0561/1152] protocol: prefer wl_surface.damage_buffer This commit makes wl_surface.damage_buffer preferred over wl_surface.damage. wl_surface.damage can be implemented in a non-optimal way by the compositor (e.g. by always damaging the whole buffer). Having two requests makes it complicated for the compositor to handle damage, making it necessary to transform one into the other's coordinates. Moreover, integration with wp_viewporter is tricky. Signed-off-by: Simon Ser Acked-by: Pekka Paalanen Reviewed-by: Derek Foreman --- protocol/wayland.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 802d4331..ea046235 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1397,9 +1397,9 @@ and clears pending damage. The server will clear the current damage as it repaints the surface. - Alternatively, damage can be posted with wl_surface.damage_buffer - which uses buffer coordinates instead of surface coordinates, - and is probably the preferred and intuitive way of doing this. + Note! New clients should not use this request. Instead damage can be + posted with wl_surface.damage_buffer which uses buffer coordinates + instead of surface coordinates. From 10c1f37a7c75a2b9a9702e0646bf2865ed88e147 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Tue, 20 Nov 2018 18:02:49 +1100 Subject: [PATCH 0562/1152] server: Split out varargs version of wl_resource_post_error. This will allow other wrappers around wl_resource_post_error to accept variable argument lists. Signed-off-by: Christopher James Halse Rogers Acked-by: Pekka Paalanen Reviewed-by: Pekka Paalanen --- src/wayland-server.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index eae8d2e7..c0ad229b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -273,17 +273,14 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...) wl_resource_queue_event_array(resource, opcode, args); } -WL_EXPORT void -wl_resource_post_error(struct wl_resource *resource, - uint32_t code, const char *msg, ...) +static void +wl_resource_post_error_vargs(struct wl_resource *resource, + uint32_t code, const char *msg, va_list argp) { struct wl_client *client = resource->client; char buffer[128]; - va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof buffer, msg, ap); - va_end(ap); + vsnprintf(buffer, sizeof buffer, msg, argp); /* * When a client aborts, its resources are destroyed in id order, @@ -298,6 +295,18 @@ wl_resource_post_error(struct wl_resource *resource, wl_resource_post_event(client->display_resource, WL_DISPLAY_ERROR, resource, code, buffer); client->error = 1; + +} + +WL_EXPORT void +wl_resource_post_error(struct wl_resource *resource, + uint32_t code, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + wl_resource_post_error_vargs(resource, code, msg, ap); + va_end(ap); } static void From d325140289d5767cdef5fc31f7d89b451c1066aa Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Tue, 20 Nov 2018 18:02:50 +1100 Subject: [PATCH 0563/1152] proto, server: Add internal server error message. (v2) Many languages such as C++ or Rust have an unwinding error-reporting mechanism. Code in these languages can (and must!) wrap request handling callbacks in unwind guards to avoid undefined behaviour. As a consequence such code will detect internal server errors, but have no way to communicate such failures to the client. This adds a WL_DISPLAY_ERROR_IMPLEMENTATION error to wl_display so that such code can notify (and disconnect) clients which hit internal bugs. While servers can currently abuse other wl_display errors for the same effect, adding an explicit error code allows clients to tell the difference between errors which are their fault and errors which are the server's fault. This is particularly interesting for automated bug reporting. v2: Rename error from "internal" to "implementation", in sympathy with X11's BadImplementation error. Add more justification in the commit message. Signed-off-by: Christopher James Halse Rogers Acked-by: Pekka Paalanen Reviewed-by: Pekka Paalanen --- protocol/wayland.xml | 2 ++ src/wayland-client.c | 3 +++ src/wayland-server-core.h | 4 ++++ src/wayland-server.c | 24 +++++++++++++++++++++++ tests/display-test.c | 40 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index ea046235..27c07c8d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -94,6 +94,8 @@ summary="method doesn't exist on the specified interface"/> + diff --git a/src/wayland-client.c b/src/wayland-client.c index 0ccfc660..b0805f14 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -185,6 +185,9 @@ display_protocol_error(struct wl_display *display, uint32_t code, case WL_DISPLAY_ERROR_NO_MEMORY: err = ENOMEM; break; + case WL_DISPLAY_ERROR_IMPLEMENTATION: + err = EPROTO; + break; default: err = EFAULT; } diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 2e725d92..3e0272b5 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -324,6 +324,10 @@ wl_client_get_object(struct wl_client *client, uint32_t id); void wl_client_post_no_memory(struct wl_client *client); +void +wl_client_post_implementation_error(struct wl_client *client, + const char* msg, ...) WL_PRINTF(2,3); + void wl_client_add_resource_created_listener(struct wl_client *client, struct wl_listener *listener); diff --git a/src/wayland-server.c b/src/wayland-server.c index c0ad229b..19f6a760 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -650,6 +650,30 @@ wl_client_post_no_memory(struct wl_client *client) WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); } +/** Report an internal server error + * + * \param client The client object + * \param msg A printf-style format string + * \param ... Format string arguments + * + * Report an unspecified internal implementation error and disconnect + * the client. + * + * \memberof wl_client + */ +WL_EXPORT void +wl_client_post_implementation_error(struct wl_client *client, + char const *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + wl_resource_post_error_vargs(client->display_resource, + WL_DISPLAY_ERROR_IMPLEMENTATION, + msg, ap); + va_end(ap); +} + WL_EXPORT void wl_resource_post_no_memory(struct wl_resource *resource) { diff --git a/tests/display-test.c b/tests/display-test.c index 9b49a0ec..6d98cc77 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -419,6 +419,46 @@ TEST(post_nomem_tst) display_destroy(d); } +static void +post_implementation_error_main(void) +{ + struct client *c = client_connect(); + struct wl_seat *seat = client_get_seat(c); + uint32_t object_id, protocol_error; + const struct wl_interface *interface; + + assert(stop_display(c, 1) == -1); + int err = wl_display_get_error(c->wl_display); + fprintf(stderr, "Err is %i\n", err); + assert(err == EPROTO); + protocol_error = wl_display_get_protocol_error(c->wl_display, + &interface, + &object_id); + assert(protocol_error == WL_DISPLAY_ERROR_IMPLEMENTATION); + assert(interface == &wl_display_interface); + + wl_proxy_destroy((struct wl_proxy *) seat); + client_disconnect_nocheck(c); +} + +TEST(post_internal_error_tst) +{ + struct display *d = display_create(); + struct client_info *cl; + + wl_global_create(d->wl_display, &wl_seat_interface, + 1, d, bind_seat); + + cl = client_create_noarg(d, post_implementation_error_main); + display_run(d); + + wl_client_post_implementation_error(cl->wl_client, "Error %i", 20); + + display_resume(d); + + display_destroy(d); +} + static void register_reading(struct wl_display *display) { From 6afb152122f242d39c886bffa02c55d764e20fe8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 29 Jan 2019 22:00:40 +0000 Subject: [PATCH 0564/1152] Print NULL strings as "nil" in wl_closure_print Calling printf("%s", NULL) is undefined behaviour. Signed-off-by: Simon Ser Reviewed-by: Pekka Paalanen --- src/connection.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index f9652107..474c97b5 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1278,7 +1278,10 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send) wl_fixed_to_double(closure->args[i].f)); break; case 's': - fprintf(stderr, "\"%s\"", closure->args[i].s); + if (closure->args[i].s) + fprintf(stderr, "\"%s\"", closure->args[i].s); + else + fprintf(stderr, "nil"); break; case 'o': if (closure->args[i].o) From d7b0b7922eb956d4bda5c102495da95e505d549b Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Fri, 10 Aug 2018 13:14:37 +0100 Subject: [PATCH 0565/1152] TODO: remove "SDL port", it's been done by now Upstream SDL supports Wayland since v2.0.4 (June 2015): https://forums.libsdl.org/viewtopic.php?t=11294 Just set SDL_VIDEODRIVER=wayland and SDL will do the right thing :) Signed-off-by: Eric Engestrom Reviewed-by: Pekka Paalanen --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 8cb8d346..88fa5cc9 100644 --- a/TODO +++ b/TODO @@ -102,9 +102,6 @@ Clients and ports - Investigate DirectFB on Wayland (or is that Wayland on DirectFB?) - - SDL port, bnf has work in progress here: - http://cgit.freedesktop.org/~bnf/sdl-wayland/ - Ideas From a94b77d0a65943232abd48128b17227a8c5e1ddc Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 19 Feb 2019 13:32:36 -0600 Subject: [PATCH 0566/1152] configure.ac: bump version to 1.16.91 for the alpha release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 18fb6492..495e1a65 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [16]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 8c121e10178070f23a06c438a292703fe76d5c06 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Oct 2018 09:13:04 +0000 Subject: [PATCH 0567/1152] protocol: warn clients about some wl_output properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All wl_output properties don't always make sense for all compositors. Some compositors might not implement a "global compositor space", (e.g. 3D compositors) in which case properties like x and y don't make sense. Some compositors might expose virtual outputs, in which case modes, make and model are not relevant. In a lot of these situations, information from xdg_output is better suited. Compositors also expose output refresh rate, which shouldn't be used for synchronization purposes. Signed-off-by: Simon Ser Reviewed-by: Daniel Stone Reviewed-by: Jonas Ådahl Reviewed-by: Derek Foreman --- protocol/wayland.xml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 27c07c8d..b1c930d9 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2407,6 +2407,13 @@ The physical size can be set to zero if it doesn't make sense for this output (e.g. for projectors or virtual outputs). + + Note: wl_output only advertises partial information about the output + position and identification. Some compositors, for instance those not + implementing a desktop-style output layout or those exposing virtual + outputs, might fake this information. Instead of using x and y, clients + should use xdg_output.logical_position. Instead of using make and model, + clients should use xdg_output.name and xdg_output.description. @@ -2451,7 +2458,17 @@ the output device. This is not necessarily the same as the output size in the global compositor space. For instance, the output may be scaled, as described in wl_output.scale, - or transformed, as described in wl_output.transform. + or transformed, as described in wl_output.transform. Clients + willing to retrieve the output size in the global compositor + space should use xdg_output.logical_size instead. + + Clients should not use the refresh rate to schedule frames. Instead, + they should use the wl_surface.frame event or the presentation-time + protocol. + + Note: this information is not always meaningful for all outputs. Some + compositors, such as those exposing virtual outputs, might fake the + refresh rate or the size. From c70fd8a812d74b5ef6fcba1287b409f4f8821e91 Mon Sep 17 00:00:00 2001 From: Leonid Bobrov via wayland-devel Date: Wed, 13 Feb 2019 13:39:06 +0200 Subject: [PATCH 0568/1152] tests: fix main symbol duplication So far I got these errors before patching: libtool: link: cc -o .libs/headers-test -pthread -Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden -O2 -pipe tests/headers-test.o tests/headers-protocol-test.o tests/headers-protocol-core-test.o /tmp/obj/wayland-1.16.0/build-amd64/.libs/libtest-runner.a -L.libs -lwayland-client -lffi -lm -lwayland-server -lkvm -Wl,-rpath-link,/usr/local/lib ld: error: duplicate symbol: main >>> defined at headers-test.c:53 (/tmp/obj/wayland-1.16.0/wayland-1.16.0/tests/headers-test.c:53) >>> tests/headers-test.o:(main) >>> defined at test-runner.c:377 (/tmp/obj/wayland-1.16.0/wayland-1.16.0/tests/test-runner.c:377) >>> test-runner.o:(.text+0x250) in archive /tmp/obj/wayland-1.16.0/build-amd64/.libs/libtest-runner.a libtool: link: cc -o .libs/exec-fd-leak-checker -pthread -Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden -O2 -pipe tests/exec-fd-leak-checker.o /tmp/obj/wayland-1.16.0/build-amd64/.libs/libtest-runner.a -L.libs -lwayland-client -lffi -lm -lwayland-server -lkvm -Wl,-rpath-link,/usr/local/lib ld: error: duplicate symbol: main >>> defined at exec-fd-leak-checker.c:57 (/tmp/obj/wayland-1.16.0/wayland-1.16.0/tests/exec-fd-leak-checker.c:57) >>> tests/exec-fd-leak-checker.o:(main) >>> defined at test-runner.c:377 (/tmp/obj/wayland-1.16.0/wayland-1.16.0/tests/test-runner.c:377) >>> test-runner.o:(.text+0x250) in archive /tmp/obj/wayland-1.16.0/build-amd64/.libs/libtest-runner.a Makefile.am: error: object 'tests/test-helpers.$(OBJEXT)' created both with libtool and without libtool: link: cc -o .libs/fixed-benchmark -pthread -Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden -O2 -pipe tests/fixed-benchmark.o /tmp/obj/wayland-1.16.0/build-amd64/.libs/libtest-runner.a -L.libs -lwayland-client -lffi -lm -lwayland-server -lkvm -Wl,-rpath-link,/usr/local/lib ld: error: duplicate symbol: main >>> defined at fixed-benchmark.c:100 (/tmp/obj/wayland-1.16.0/wayland-1.16.0/tests/fixed-benchmark.c:100) >>> tests/fixed-benchmark.o:(main) >>> defined at test-runner.c:377 (/tmp/obj/wayland-1.16.0/wayland-1.16.0/tests/test-runner.c:377) >>> test-runner.o:(.text+0x250) in archive /tmp/obj/wayland-1.16.0/build-amd64/.libs/libtest-runner.a This commit fixes all of that. Signed-off-by: Leonid Bobrov Reviewed-by: Pekka Paalanen --- Makefile.am | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 697c517b..f47d0559 100644 --- a/Makefile.am +++ b/Makefile.am @@ -210,12 +210,15 @@ noinst_PROGRAMS = \ exec-fd-leak-checker \ fixed-benchmark -noinst_LTLIBRARIES += libtest-runner.la +noinst_LTLIBRARIES += \ + libtest-runner.la \ + libtest-helpers.la + +libtest_helpers_la_SOURCES = tests/test-helpers.c libtest_runner_la_SOURCES = \ tests/test-runner.c \ tests/test-runner.h \ - tests/test-helpers.c \ tests/test-compositor.h \ tests/test-compositor.c libtest_runner_la_LIBADD = \ @@ -223,9 +226,9 @@ libtest_runner_la_LIBADD = \ libwayland-util.la \ libwayland-client.la \ libwayland-server.la \ + libtest-helpers.la \ -lrt -ldl $(FFI_LIBS) - array_test_SOURCES = tests/array-test.c array_test_LDADD = libtest-runner.la client_test_SOURCES = tests/client-test.c @@ -270,7 +273,6 @@ protocol_logger_test_LDADD = libtest-runner.la headers_test_SOURCES = tests/headers-test.c \ tests/headers-protocol-test.c \ tests/headers-protocol-core-test.c -headers_test_LDADD = libtest-runner.la nodist_headers_test_SOURCES = \ protocol/wayland-server-protocol-core.h \ protocol/wayland-client-protocol-core.h @@ -280,13 +282,12 @@ cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp endif fixed_benchmark_SOURCES = tests/fixed-benchmark.c -fixed_benchmark_LDADD = libtest-runner.la os_wrappers_test_SOURCES = tests/os-wrappers-test.c os_wrappers_test_LDADD = libtest-runner.la exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c -exec_fd_leak_checker_LDADD = libtest-runner.la +exec_fd_leak_checker_LDADD = libtest-helpers.la EXTRA_DIST += tests/scanner-test.sh \ protocol/tests.xml \ From 75bd70c0b335a8bbbbb030e5be1557a4bc02a86d Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 5 Mar 2019 17:22:24 -0600 Subject: [PATCH 0569/1152] configure.ac: bump to version 1.16.92 for the beta release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 495e1a65..0ccc3bbc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [16]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From 15cba8b07499feb43ee56510b3761d8ddabda45a Mon Sep 17 00:00:00 2001 From: Chris Billington Date: Wed, 6 Mar 2019 15:54:31 -0500 Subject: [PATCH 0570/1152] wayland-util.h: add forward declaration for wl_object The definition of wl_argument in wayland-util.h references wl_object, so wl_object ought to be defined in wayland-util.h. This resolves gitlab issue #78. Fixes: https://gitlab.freedesktop.org/wayland/wayland/issues/78 Signed-off-by: Pekka Paalanen --- src/wayland-util.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/wayland-util.h b/src/wayland-util.h index b6cbe0ea..2115f5c7 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -68,6 +68,20 @@ extern "C" { #define WL_PRINTF(x, y) #endif +/** \class wl_object + * + * \brief A protocol object. + * + * A `wl_object` is an opaque struct identifying the protocol object + * underlying a `wl_proxy` or `wl_resource`. + * + * \note Functions accessing a `wl_object` are not normally used by client code. + * Clients should normally use the higher level interface generated by the + * scanner to interact with compositor objects. + * + */ +struct wl_object; + /** * Protocol message signature * From 808bca896563fbf4d3d613f0748c898415c852f4 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 26 Feb 2019 14:51:10 +0200 Subject: [PATCH 0571/1152] contributing: use Gitlab merge request workflow The experience from Weston shows that the Gitlab merge request based workflow works really well. Recently there have also been issues with the mailing list that have made the email based workflow more painful than it used to be. Those issues might have been temporary or occasional, but they probably are only going to increase. The MR workflow is different, it has its issues (https://gitlab.freedesktop.org/freedesktop/freedesktop/issues/74) and we likely lose the explicit Reviewed-by etc. tags from commit messages, but it is also much easier to work with: no more whitespace damaged patches, lost email, setting up git-send-email; we gain automated CI before any human reviewer even looks at anything, and people can jump in to an ongoing discussion even if they weren't subscribed before. If you still want email, you can subscribe to that selectively(!) in Gitlab yourself. This text has been copied from Weston's CONTRIBUTING.md of the 5.0.91 release and slightly altered for Wayland. Fixes: https://gitlab.freedesktop.org/wayland/wayland/issues/49 v2: fixed two left-over mentions of Weston Signed-off-by: Pekka Paalanen v1 Reviewed-by: Simon Ser Reviewed-by: Daniel Stone Reviewed-by: Scott Anderson Acked-by: Ian Ray Acked-by: Derek Foreman --- CONTRIBUTING.md | 139 +++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 71 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 686ed63f..dcc9f56f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,8 +4,46 @@ Contributing to Wayland Sending patches --------------- -Patches should be sent to **wayland-devel@lists.freedesktop.org**, using -`git send-email`. See [git documentation] for help. +Patches should be sent via +[GitLab merge requests](https://docs.gitlab.com/ce/gitlab-basics/add-merge-request.html). +Wayland is +[hosted on freedesktop.org's GitLab](https://gitlab.freedesktop.org/wayland/wayland/): +in order to submit code, you should create an account on this GitLab instance, +fork the core Wayland repository, push your changes to a branch in your new +repository, and then submit these patches for review through a merge request. + +Wayland formerly accepted patches via `git-send-email`, sent to +**wayland-devel@lists.freedesktop.org**; these were +[tracked using Patchwork](https://patchwork.freedesktop.org/project/wayland/). +Some old patches continue to be sent this way, and we may accept small new +patches sent to the list, but please send all new patches through GitLab merge +requests. + + +Formatting and separating commits +--------------------------------- + +Unlike many projects using GitHub and GitLab, Wayland has a +[linear, 'recipe' style history](http://www.bitsnbites.eu/git-history-work-log-vs-recipe/). +This means that every commit should be small, digestible, stand-alone, and +functional. Rather than a purely chronological commit history like this: + + connection: plug a fd leak + plug another fd leak + connection: init fds to -1 + close all fds + refactor checks into a new function + don't close fds we handed out + +we aim to have a clean history which only reflects the final state, broken up +into functional groupings: + + connection: Refactor out closure allocation + connection: Clear fds we shouldn't close to -1 + connection: Make wl_closure_destroy() close fds of undispatched closures + +This ensures that the final patch series only contains the final state, +without the changes and missteps taken along the development process. The first line of a commit message should contain a prefix indicating what part is affected by the patch followed by one sentence that @@ -45,7 +83,7 @@ We won't reject patches that lack S-o-b, but it is strongly recommended. When you re-send patches, revised or not, it would be very good to document the changes compared to the previous revision in the commit message and/or the -cover letter. If you have already received Reviewed-by or Acked-by tags, you +merge request. If you have already received Reviewed-by or Acked-by tags, you should evaluate whether they still apply and include them in the respective commit messages. Otherwise the tags may be lost, reviewers miss the credit they deserve, and the patches may cause redundant review effort. @@ -54,78 +92,37 @@ deserve, and the patches may cause redundant review effort. Tracking patches and following up --------------------------------- -[Wayland Patchwork](http://patchwork.freedesktop.org/project/wayland/list/) is -used for tracking patches to Wayland. Xwayland patches are tracked with the -[Xorg project](https://patchwork.freedesktop.org/project/Xorg/list/) -instead. Weston uses -[GitLab merge requests](https://gitlab.freedesktop.org/wayland/weston/merge_requests) -for code review, and does not use mailing list review at all. +Once submitted to GitLab, your patches will be reviewed by the Wayland +development team on GitLab. Review may be entirely positive and result in your +code landing instantly, in which case, great! You're done. However, we may ask +you to make some revisions: fixing some bugs we've noticed, working to a +slightly different design, or adding documentation and tests. -Libinput patches, even though they use the same mailing list as -Wayland, are not tracked in the Wayland Patchwork. +If you do get asked to revise the patches, please bear in mind the notes above. +You should use `git rebase -i` to make revisions, so that your patches follow +the clear linear split documented above. Following that split makes it easier +for reviewers to understand your work, and to verify that the code you're +submitting is correct. -The following applies only to Wayland. +A common request is to split single large patch into multiple patches. This can +happen, for example, if when adding a new feature you notice a bug elsewhere +which you need to fix to progress. Separating these changes into separate +commits will allow us to verify and land the bugfix quickly, pushing part of +your work for the good of everyone, whilst revision and discussion continues on +the larger feature part. It also allows us to direct you towards reviewers who +best understand the different areas you are working on. -If a patch is not found in Patchwork, there is a high possibility for it to be -forgotten. Patches attached to bug reports or not arriving to the mailing list -because of e.g. subscription issues will not be in Patchwork because Patchwork -only collects patches sent to the list. +When you have made any requested changes, please rebase the commits, verify +that they still individually look good, then force-push your new branch to +GitLab. This will update the merge request and notify everyone subscribed to +your merge request, so they can review it again. -When you send a revised version of a patch, it would be very nice to mark your -old patch as superseded (or rejected, if that is applicable). You can change -the status of your own patches by registering to Patchwork - ownership is -identified by email address you use to register. Updating your patch status -appropriately will help maintainer work. - -The following patch states are found in Patchwork: - -- **New**: - Patches under discussion or not yet processed. - -- **Under review**: - Mostly unused state. - -- **Accepted**: - The patch is merged in the master branch upstream, as is or slightly - modified. - -- **Rejected**: - The idea or approach is rejected and cannot be fixed by revising - the patch. - -- **RFC**: - Request for comments, not meant to be merged as is. - -- **Not applicable**: - The email was not actually a patch, or the patch is not for Wayland. - Libinput patches are usually automatically ignored by Wayland - Patchwork, but if they get through, they will be marked as Not - applicable. - -- **Changes requested**: - Reviewers determined that changes to the patch are needed. The - submitter is expected to send a revised version. (You should - not wait for your patch to be set to this state before revising, - though.) - -- **Awaiting upstream**: - Mostly unused as the patch is waiting for upstream actions but - is not shown in the default list, which means it is easy to - overlook. - -- **Superseded**: - A revised version of the patch has been submitted. - -- **Deferred**: - Used mostly during freeze periods before releases, to temporarily - hide patches that cannot be merged during a freeze. - -Note, that in the default listing, only patches in *New* or *Under review* are -shown. - -There is also a command line interface to Patchwork called `pwclient`, see -http://patchwork.freedesktop.org/project/wayland/ -for links where to get it and the sample `.pwclientrc` for Wayland. +There are also +[many GitLab CLI clients](https://about.gitlab.com/applications/#cli-clients), +if you prefer to avoid the web interface. It may be difficult to follow review +comments without using the web interface though, so we do recommend using this +to go through the review process, even if you use other clients to track the +list of available patches. Coding style From 446047edf2da8b3ce899f28253f14dff18d9f4d7 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 4 Mar 2019 13:45:58 +0200 Subject: [PATCH 0572/1152] tests: add request_bogus_size This attempts to reproduce the error conditions from https://gitlab.freedesktop.org/wayland/wayland/issues/52 and make it crash. While the crash was repeatable in my tests, it depends on garbage on stack leading to access of invalid memory, which is not guaranteed. This is a FAIL_TEST, so that the following fix commit can be verified. Signed-off-by: Pekka Paalanen Reviewed-by: Simon Ser --- tests/connection-test.c | 87 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/tests/connection-test.c b/tests/connection-test.c index 018e2ac0..c3496e68 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -752,3 +752,90 @@ TEST(closure_leaks_after_error) display_destroy(d); } + +/** Raw read from socket expecting wl_display.error + * + * \param sockfd The socket to read from. + * \param expected_error The expected wl_display error code. + * + * Reads the socket and manually parses one message, expecting it to be a + * wl_display.error with the wl_display as the originating object. + * Asserts that the received error code is expected_error. + */ +static void +expect_error_recv(int sockfd, uint32_t expected_error) +{ + uint32_t buf[1024]; + ssize_t slen; + uint32_t opcode; + int str_len; + + slen = recv(sockfd, buf, sizeof buf, 0); + assert(slen >= 2 * (ssize_t)sizeof (uint32_t)); + opcode = buf[1] & 0xffff; + fprintf(stderr, "Received %zd bytes, object %u, opcode %u\n", + slen, buf[0], opcode); + + /* check error event */ + assert(buf[0] == 1); + assert(opcode == WL_DISPLAY_ERROR); + + str_len = buf[4]; + assert(str_len > 0); + assert(str_len <= slen - 5 * (ssize_t)sizeof (uint32_t)); + fprintf(stderr, "Error event on object %u, code %u, message \"%*s\"\n", + buf[2], buf[3], str_len, (const char *)&buf[5]); + + assert(buf[3] == expected_error); +} + +/* A test for https://gitlab.freedesktop.org/wayland/wayland/issues/52 + * trying to provoke a read from uninitialized memory in + * wl_connection_demarshal() for sender_id and opcode. + * + * This test might not fail as is even with #52 unfixed, since there is no way + * to detect what happens and the crash with zero size depends on stack content. + * However, running under Valgrind would point out invalid reads and use of + * uninitialized values. + */ +FAIL_TEST(request_bogus_size) +{ + struct wl_display *display; + struct wl_client *client; + int s[2]; + uint32_t msg[3]; + int bogus_size; + + test_set_timeout(1); + + /* + * The manufactured message has real size 12. Test all bogus sizes + * smaller than that, and zero as the last one since wl_closure_init + * handles zero specially and having garbage in the stack makes it more + * likely to crash in wl_connection_demarshal. + */ + for (bogus_size = 11; bogus_size >= 0; bogus_size--) { + fprintf(stderr, "* bogus size %d\n", bogus_size); + + assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + display = wl_display_create(); + assert(display); + client = wl_client_create(display, s[0]); + assert(client); + + /* manufacture a request that lies about its size */ + msg[0] = 1; /* sender id: wl_display */ + msg[1] = (bogus_size << 16) | WL_DISPLAY_SYNC; /* size and opcode */ + msg[2] = 2; /* sync argument: new_id for wl_callback */ + + assert(send(s[1], msg, sizeof msg, 0) == sizeof msg); + + wl_event_loop_dispatch(wl_display_get_event_loop(display), 0); + + expect_error_recv(s[1], WL_DISPLAY_ERROR_INVALID_METHOD); + + /* Do not wl_client_destroy, the error already caused it. */ + close(s[1]); + wl_display_destroy(display); + } +} From bace3cd819798571189671b68590adff3fd40997 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 6 Mar 2019 13:42:23 +0200 Subject: [PATCH 0573/1152] connection: fix demarshal of invalid header The size argument to wl_connection_demarshal() is taken from the message by the caller wl_client_connection_data(), therefore 'size' is untrusted data controllable by a Wayland client. The size should always be at least the header size, otherwise the header is invalid. If the size is smaller than header size, it leads to reading past the end of allocated memory. Furthermore if size is zero, wl_closure_init() changes behaviour and leaves num_arrays uninitialized, leading to access of arbitrary memory. Check that 'size' fits at least the header. The space for arguments is already properly checked. This makes the request_bogus_size test free of errors under Valgrind. Fixes: https://gitlab.freedesktop.org/wayland/wayland/issues/52 Signed-off-by: Pekka Paalanen Reviewed-by: Simon Ser --- src/connection.c | 8 ++++++++ tests/connection-test.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index 474c97b5..7fba999b 100644 --- a/src/connection.c +++ b/src/connection.c @@ -695,6 +695,14 @@ wl_connection_demarshal(struct wl_connection *connection, struct wl_closure *closure; struct wl_array *array_extra; + /* Space for sender_id and opcode */ + if (size < 2 * sizeof *p) { + wl_log("message too short, invalid header\n"); + wl_connection_consume(connection, size); + errno = EINVAL; + return NULL; + } + closure = wl_closure_init(message, size, &num_arrays, NULL); if (closure == NULL) { wl_connection_consume(connection, size); diff --git a/tests/connection-test.c b/tests/connection-test.c index c3496e68..a06a3cca 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -798,7 +798,7 @@ expect_error_recv(int sockfd, uint32_t expected_error) * However, running under Valgrind would point out invalid reads and use of * uninitialized values. */ -FAIL_TEST(request_bogus_size) +TEST(request_bogus_size) { struct wl_display *display; struct wl_client *client; From cbdfa87ce3223c10355b7c3869c0e42cf2e125e3 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 13 Mar 2019 21:27:59 -0500 Subject: [PATCH 0574/1152] configure.ac: bump version to 1.16.93 for the RC1 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0ccc3bbc..d67f553b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [16]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From e091839dd08354289e501a47219e0c7a6472dff3 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 20 Mar 2019 19:54:18 -0500 Subject: [PATCH 0575/1152] configure.ac: bump to version 1.17.0 for the official release --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d67f553b..8d56f2bb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [16]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [17]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From dd3ba21457648db411d14b5b308e6a93aa401a4e Mon Sep 17 00:00:00 2001 From: Leonid Bobrov Date: Mon, 25 Feb 2019 19:38:02 +0200 Subject: [PATCH 0576/1152] configure: detect libdl and librt Signed-off-by: Leonid Bobrov --- Makefile.am | 6 +++--- configure.ac | 6 ++++++ m4/weston.m4 | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 m4/weston.m4 diff --git a/Makefile.am b/Makefile.am index f47d0559..489f5818 100644 --- a/Makefile.am +++ b/Makefile.am @@ -71,7 +71,7 @@ nodist_include_HEADERS = \ protocol/wayland-client-protocol.h libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread -libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la -lrt -lm +libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm libwayland_server_la_LDFLAGS = -version-info 1:0:1 libwayland_server_la_SOURCES = \ src/wayland-server.c \ @@ -83,7 +83,7 @@ nodist_libwayland_server_la_SOURCES = \ protocol/wayland-protocol.c libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread -libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la -lrt -lm +libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm libwayland_client_la_LDFLAGS = -version-info 3:0:3 libwayland_client_la_SOURCES = \ src/wayland-client.c @@ -227,7 +227,7 @@ libtest_runner_la_LIBADD = \ libwayland-client.la \ libwayland-server.la \ libtest-helpers.la \ - -lrt -ldl $(FFI_LIBS) + $(RT_LIBS) $(DL_LIBS) $(FFI_LIBS) array_test_SOURCES = tests/array-test.c array_test_LDADD = libtest-runner.la diff --git a/configure.ac b/configure.ac index 8d56f2bb..7ecb4b8e 100644 --- a/configure.ac +++ b/configure.ac @@ -65,6 +65,12 @@ AC_SUBST(GCC_CFLAGS) AC_CHECK_HEADERS([sys/prctl.h]) AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl]) +# *BSD don't have libdl, but they have its functions in libc +WESTON_SEARCH_LIBS([DL], [dl], [dlsym]) + +# OpenBSD doesn't have librt, but it has its functions in libc +WESTON_SEARCH_LIBS([RT], [rt], [clock_gettime]) + AC_ARG_ENABLE([libraries], [AC_HELP_STRING([--disable-libraries], [Disable compilation of wayland libraries])], diff --git a/m4/weston.m4 b/m4/weston.m4 new file mode 100644 index 00000000..636f9fb0 --- /dev/null +++ b/m4/weston.m4 @@ -0,0 +1,37 @@ +dnl +dnl Copyright © 2016 Quentin “Sardem FF7” Glidic +dnl +dnl Permission is hereby granted, free of charge, to any person obtaining a +dnl copy of this software and associated documentation files (the "Software"), +dnl to deal in the Software without restriction, including without limitation +dnl the rights to use, copy, modify, merge, publish, distribute, sublicense, +dnl and/or sell copies of the Software, and to permit persons to whom the +dnl Software is furnished to do so, subject to the following conditions: +dnl +dnl The above copyright notice and this permission notice (including the next +dnl paragraph) shall be included in all copies or substantial portions of the +dnl Software. +dnl +dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +dnl DEALINGS IN THE SOFTWARE. +dnl + +dnl WESTON_SEARCH_LIBS(PREFIX, search-libs, function, [action-if-found], [action-if-not-found], [other-libraries]) +dnl WESTON_SEARCH_LIBS is a wrapper around AC_SEARCH_LIBS with a little difference: +dnl action-if-found is called even if no library is required +AC_DEFUN([WESTON_SEARCH_LIBS], [ + weston_save_LIBS=${LIBS} + AC_SEARCH_LIBS([$3], [$2], [$4], [$5], [$6]) + AS_CASE([${ac_cv_search_][$3][}], + ['none required'], [$4], + [no], [], + [$1][_LIBS=${ac_cv_search_][$3][}] + ) + AC_SUBST([$1][_LIBS]) + LIBS=${weston_save_LIBS} +]) From ca5a59ec4cd7e88636d650b47ae4b976f3e47b6a Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 8 Apr 2019 10:26:24 +0300 Subject: [PATCH 0577/1152] configure.ac: reopen master for regular development Signed-off-by: Pekka Paalanen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7ecb4b8e..1c147a95 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [17]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) From b8933d468894b75e5c17681ff4ea533f213bbe28 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 8 Apr 2019 21:37:28 +0300 Subject: [PATCH 0578/1152] Add releasing.txt This file is imported from Weston (commit 53d7c243). Signed-off-by: Simon Ser --- releasing.txt | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 releasing.txt diff --git a/releasing.txt b/releasing.txt new file mode 100644 index 00000000..446e1ad4 --- /dev/null +++ b/releasing.txt @@ -0,0 +1,113 @@ +To make a release of Weston and/or Wayland, follow these steps. + + 0. Verify the test suites and codebase checks pass. All of the + tests should either pass or skip. + + $ make check + + 1. For Weston, verify that the wayland and wayland-protocols version + dependencies are correct, and that wayland-protocols has had a + release with any needed protocol updates. + + 2. Update the first stanza of configure.ac to the intended versions + for Weston and libweston. + + For Weston's x.y.0 releases, if libweston_major_version is greater than + weston_major_version, bump the Weston version numbers (major, minor, + micro) to match the libweston version numbers (major, minor, patch). + + Additionally for all Weston releases, if libweston's + major.minor.patch version is less than Weston's major.minor.micro + version, bump libweston version numbers to match the Weston + version numbers. + + Weston releases are made with the Weston version number, not with the + libweston version number. + + Then commit your changes: + + $ export RELEASE_NUMBER="x.y.z" + $ export RELEASE_NAME="[alpha|beta|RC1|RC2|official|point]" + $ git status + $ git commit configure.ac -m "configure.ac: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release" + $ git push + + 3. For Weston releases, install Xwayland, either from your distro or + manually (see http://wayland.freedesktop.org/building.html). If + you install it to a location other than /usr/bin/Xwayland, specify + this in the following env var: + + XWAYLAND=$(which Xwayland) # Or specify your own path + export DISTCHECK_CONFIGURE_FLAGS="--with-xserver-path=$XWAYLAND" + + If you're using a locally installed libinput or other dependency + libraries, you'll likely need to set a few other environment + variables: + + export WLD="" + export LD_LIBRARY_PATH=$WLD/lib + export PKG_CONFIG_PATH=$WLD/lib/pkgconfig:$WLD/share/pkgconfig/ + + 4. Run the release.sh script to generate the tarballs, sign and + upload them, and generate a release announcement template. + This script can be obtained from X.org's modular package: + + http://cgit.freedesktop.org/xorg/util/modular/tree/release.sh + + The script supports a --dry-run option to test it without actually + doing a release. If the script fails on the distcheck step due to + a testsuite error that can't be fixed for some reason, you can + skip testsuite by specifying the --dist argument. Pass --help to + see other supported options. + + $ release.sh . + + For Wayland official and point releases, also publish the publican + documentation to wayland.freedesktop.org: + + $ ./publish-doc + + 5. Compose the release announcements. The script will generate + *.x.y.z.announce files with a list of changes and tags, one for + wayland, one for weston. Prepend these with a human-readable + listing of the most notable changes. For x.y.0 releases, indicate + the schedule for the x.y+1.0 release. + + 6. pgp sign the release announcements and send them to + wayland-devel@lists.freedesktop.org + + 7. Update releases.html in wayland-web with links to tarballs and + the release email URL. + + The wl_register_release script in wayland-web will generate an HTML + snippet that can be pasted into releases.html (or e.g. in emacs + insert it via "C-u M-! scripts/wl_register_release x.y.z") and + customized. + + Once satisfied: + + $ git commit ./releases.html -m "releases: Add ${RELEASE_NUMBER} release" + $ git push + $ ./deploy + + 8. Update topic in #wayland to point to the release announcement URL + +For x.y.0 releases, also create the release series x.y branch. The x.y +branch is for bug fixes and conservative changes to the x.y.0 release, +and is where we create x.y.z releases from. Creating the x.y branch +opens up master for new development and lets new development move on. +We've done this both after the x.y.0 release (to focus development on +bug fixing for the x.y.1 release for a little longer) or before the +x.y.0 release (like we did with the 1.5.0 release, to unblock master +development early). + + $ git branch x.y [sha] + $ git push origin x.y + +The master branch's configure.ac version should always be (at least) +x.y.90, with x.y being the most recent stable branch. The stable +branch's configure.ac version is just whatever was most recently +released from that branch. + +For stable branches, we commit fixes to master first, then cherry-pick +them back to the stable branch. From 724bf08e2fd0d4a9ca769d3f7a47e54f8ed021a1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 11 Apr 2019 19:46:53 +0300 Subject: [PATCH 0579/1152] releasing: adapt for Wayland Remove Weston-specific bits, strip off outdated instructions. Signed-off-by: Simon Ser --- releasing.txt | 49 +++++++------------------------------------------ 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/releasing.txt b/releasing.txt index 446e1ad4..4a9925e1 100644 --- a/releasing.txt +++ b/releasing.txt @@ -1,28 +1,11 @@ -To make a release of Weston and/or Wayland, follow these steps. +To make a release of Wayland, follow these steps. 0. Verify the test suites and codebase checks pass. All of the tests should either pass or skip. $ make check - 1. For Weston, verify that the wayland and wayland-protocols version - dependencies are correct, and that wayland-protocols has had a - release with any needed protocol updates. - - 2. Update the first stanza of configure.ac to the intended versions - for Weston and libweston. - - For Weston's x.y.0 releases, if libweston_major_version is greater than - weston_major_version, bump the Weston version numbers (major, minor, - micro) to match the libweston version numbers (major, minor, patch). - - Additionally for all Weston releases, if libweston's - major.minor.patch version is less than Weston's major.minor.micro - version, bump libweston version numbers to match the Weston - version numbers. - - Weston releases are made with the Weston version number, not with the - libweston version number. + 1. Update the first stanza of configure.ac to the intended version. Then commit your changes: @@ -32,22 +15,6 @@ To make a release of Weston and/or Wayland, follow these steps. $ git commit configure.ac -m "configure.ac: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release" $ git push - 3. For Weston releases, install Xwayland, either from your distro or - manually (see http://wayland.freedesktop.org/building.html). If - you install it to a location other than /usr/bin/Xwayland, specify - this in the following env var: - - XWAYLAND=$(which Xwayland) # Or specify your own path - export DISTCHECK_CONFIGURE_FLAGS="--with-xserver-path=$XWAYLAND" - - If you're using a locally installed libinput or other dependency - libraries, you'll likely need to set a few other environment - variables: - - export WLD="" - export LD_LIBRARY_PATH=$WLD/lib - export PKG_CONFIG_PATH=$WLD/lib/pkgconfig:$WLD/share/pkgconfig/ - 4. Run the release.sh script to generate the tarballs, sign and upload them, and generate a release announcement template. This script can be obtained from X.org's modular package: @@ -68,12 +35,12 @@ To make a release of Weston and/or Wayland, follow these steps. $ ./publish-doc 5. Compose the release announcements. The script will generate - *.x.y.z.announce files with a list of changes and tags, one for - wayland, one for weston. Prepend these with a human-readable - listing of the most notable changes. For x.y.0 releases, indicate - the schedule for the x.y+1.0 release. + *.x.y.z.announce files with a list of changes and tags. Prepend + it with a human-readable listing of the most notable changes. + For x.y.0 releases, indicate the schedule for the x.y+1.0 + release. - 6. pgp sign the release announcements and send them to + 6. PGP sign the release announcements and send them to wayland-devel@lists.freedesktop.org 7. Update releases.html in wayland-web with links to tarballs and @@ -90,8 +57,6 @@ To make a release of Weston and/or Wayland, follow these steps. $ git push $ ./deploy - 8. Update topic in #wayland to point to the release announcement URL - For x.y.0 releases, also create the release series x.y branch. The x.y branch is for bug fixes and conservative changes to the x.y.0 release, and is where we create x.y.z releases from. Creating the x.y branch From de64489b95f8bfefe3b19c7446b55914ea59e17c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 12 Apr 2019 11:27:38 +0300 Subject: [PATCH 0580/1152] releasing: fixup section numbers Signed-off-by: Simon Ser --- releasing.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/releasing.txt b/releasing.txt index 4a9925e1..1481f7cd 100644 --- a/releasing.txt +++ b/releasing.txt @@ -15,7 +15,7 @@ To make a release of Wayland, follow these steps. $ git commit configure.ac -m "configure.ac: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release" $ git push - 4. Run the release.sh script to generate the tarballs, sign and + 2. Run the release.sh script to generate the tarballs, sign and upload them, and generate a release announcement template. This script can be obtained from X.org's modular package: @@ -34,16 +34,16 @@ To make a release of Wayland, follow these steps. $ ./publish-doc - 5. Compose the release announcements. The script will generate + 3. Compose the release announcements. The script will generate *.x.y.z.announce files with a list of changes and tags. Prepend it with a human-readable listing of the most notable changes. For x.y.0 releases, indicate the schedule for the x.y+1.0 release. - 6. PGP sign the release announcements and send them to + 4. PGP sign the release announcements and send them to wayland-devel@lists.freedesktop.org - 7. Update releases.html in wayland-web with links to tarballs and + 5. Update releases.html in wayland-web with links to tarballs and the release email URL. The wl_register_release script in wayland-web will generate an HTML From b77cf862909f5cc2a4b20f0f92c586a1f135dd92 Mon Sep 17 00:00:00 2001 From: Harish Krupo Date: Fri, 19 Apr 2019 19:31:08 +0530 Subject: [PATCH 0581/1152] docs: Abort configure if docbook-xsl package is missing The docbook-xsl package includes all the stylesheets required to build the docs without internet access. Test: One way to emulate missing style sheets is to move /etc/xml/catalog file to a different location. Doing so should cause configure to fail with "checking for docbook stylesheets... no" v2: add AC_MSG_RESULT (Pekka) Signed-off-by: Harish Krupo --- configure.ac | 26 +++++++++++++------------- doc/man/Makefile.am | 4 +--- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 1c147a95..59ae244b 100644 --- a/configure.ac +++ b/configure.ac @@ -129,19 +129,6 @@ fi AC_PATH_PROG(XSLTPROC, xsltproc) AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"]) -AC_MSG_CHECKING([for docbook manpages stylesheet]) -MANPAGES_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl -AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc], - AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$MANPAGES_STYLESHEET" > /dev/null 2>&1`], - [HAVE_MANPAGES_STYLESHEET=yes])) -if test "x$HAVE_MANPAGES_STYLESHEET" = "xyes"; then - AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], true) - AC_SUBST(MANPAGES_STYLESHEET) - AC_MSG_RESULT([yes]) -else - AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], false) - AC_MSG_RESULT([no]) -fi AM_CONDITIONAL(BUILD_DOCS, [test x$enable_documentation = xyes]) if test "x$enable_documentation" = "xyes"; then @@ -177,6 +164,19 @@ if test "x$enable_documentation" = "xyes"; then [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([yes])]) + AC_MSG_CHECKING([for docbook stylesheets]) + DOCS_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl + AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc], + AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$DOCS_STYLESHEET" > /dev/null 2>&1`], + [HAVE_DOCS_STYLESHEET=yes])) + if test "x$HAVE_DOCS_STYLESHEET" != "xyes"; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Documentation build requested but docbook-xsl stylesheets are not found. Install the docbook-xsl package or disable the documentation using --disable-documentation]) + fi + + AC_MSG_RESULT([yes]) + AC_SUBST(DOCS_STYLESHEET) + AC_CONFIG_FILES([ doc/doxygen/wayland.doxygen ]) diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 41665eb2..4e6365cf 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -15,7 +15,6 @@ CLEANFILES = EXTRA_DIST = $(XML_FILES) if HAVE_XSLTPROC -if HAVE_MANPAGES_STYLESHEET CLEANFILES += $(MANPAGES) $(MANPAGES_ALIASES) EXTRA_DIST += $(MANPAGES) $(MANPAGES_ALIASES) @@ -30,7 +29,7 @@ XSLTPROC_FLAGS = \ XSLTPROC_PROCESS_MAN = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(MANPAGES_STYLESHEET) $< && \ + $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(DOCS_STYLESHEET) $< && \ $(SED) -i -e 's/^\.so \(.*\)\.\(.\)$$/\.so man\2\/\1\.\2/' $(MANPAGES_ALIASES) %.1: %.xml @@ -47,5 +46,4 @@ XSLTPROC_PROCESS_MAN = \ wl_display_connect_to_fd.3: wl_display_connect.3 -endif # HAVE_MANPAGES_STYLESHEET endif # HAVE_XSLTPROC From ea11878d00493b76f3bf4d6cf66ceef351c0a032 Mon Sep 17 00:00:00 2001 From: Harish Krupo Date: Fri, 19 Apr 2019 22:02:08 +0530 Subject: [PATCH 0582/1152] wayland.xml: document invalid_finish error in wl_data_offer.finish Explicitly state that the invalid_finish protocol error would be raised when wl_data_offer.finish request is sent for non drag-and-drop operations. Signed-off-by: Harish Krupo --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index b1c930d9..f19c5b80 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -509,6 +509,9 @@ this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. + + If wl_data_offer.finish request is received for a non drag and drop + operation, the invalid_finish protocol error is raised. From 3ab56ef8fa5aa64c07ad10fbaeb09b0c3b708ccf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 29 Sep 2018 22:25:47 +0200 Subject: [PATCH 0583/1152] protocol: allow to send a zero output refresh rate Fixed refresh rate doesn't always make sense for all outputs. In case it's not available or not relevant, allow compositors to send zero. For instance the can be the case for virtual outputs. Signed-off-by: Simon Ser --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f19c5b80..dee0ac10 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2465,6 +2465,9 @@ willing to retrieve the output size in the global compositor space should use xdg_output.logical_size instead. + The vertical refresh rate can be set to zero if it doesn't make + sense for this output (e.g. for virtual outputs). + Clients should not use the refresh rate to schedule frames. Instead, they should use the wl_surface.frame event or the presentation-time protocol. From 6ce4bbb3dd86f8526331aa42916a120e39069bf1 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 13 Apr 2019 17:30:46 -0400 Subject: [PATCH 0584/1152] scanner: error when element names will not compile This change checks that the "name" fields of the various structures in a Wayland protocol XML file will be converted into C identifiers that can be successfully compiled. For names which will be inserted as the prefix of an identifier enforce a match with [_a-zA-Z][_0-9a-zA-Z]* . For types only inserted as the suffix of an identifier (enum, entry), enforce a format of [_0-9a-zA-Z]+ . Unicode characters (and escape sequences like \u0394) are not allowed, because most older and some newer C compilers do not support them by default. For sake of simplicity, this patch does not check for collisions with reserved words or standard library names. Signed-off-by: Manuel Stoeckl --- src/scanner.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index a94be5d7..86d90c0a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -251,6 +251,11 @@ struct parse_context { unsigned int character_data_length; }; +enum identifier_role { + STANDALONE_IDENT, + TRAILING_IDENT +}; + static void * fail_on_null(void *p) { @@ -627,6 +632,50 @@ strtouint(const char *str) return (int)ret; } +/* Check that the provided string will produce valid "C" identifiers. + * + * If the string will form the prefix of an identifier in the + * generated C code, then it must match [_a-zA-Z][_0-9a-zA-Z]*. + * + * If the string will form the suffix of an identifier, then + * it must match [_0-9a-zA-Z]+. + * + * Unicode characters or escape sequences are not permitted, + * since not all C compilers support them. + * + * If the above conditions are not met, then fail() + */ +static void +validate_identifier(struct location *loc, + const char *str, + enum identifier_role role) +{ + const char *scan; + + if (!*str) { + fail(loc, "element name is empty"); + } + + for (scan = str; *scan; scan++) { + char c = *scan; + + /* we do not use the locale-dependent `isalpha` */ + bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + bool is_digit = c >= '0' && c <= '9'; + bool leading_char = (scan == str) && role == STANDALONE_IDENT; + + if (is_alpha || c == '_' || (!leading_char && is_digit)) + continue; + + if (role == TRAILING_IDENT) + fail(loc, + "'%s' is not a valid trailing identifier part", str); + else + fail(loc, + "'%s' is not a valid standalone identifier", str); + } +} + static int version_from_since(struct parse_context *ctx, const char *since) { @@ -701,6 +750,7 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no protocol name given"); + validate_identifier(&ctx->loc, name, STANDALONE_IDENT); ctx->protocol->name = xstrdup(name); ctx->protocol->uppercase_name = uppercase_dup(name); } else if (strcmp(element_name, "copyright") == 0) { @@ -712,6 +762,7 @@ start_element(void *data, const char *element_name, const char **atts) if (version == 0) fail(&ctx->loc, "no interface version given"); + validate_identifier(&ctx->loc, name, STANDALONE_IDENT); interface = create_interface(ctx->loc, name, version); ctx->interface = interface; wl_list_insert(ctx->protocol->interface_list.prev, @@ -721,6 +772,7 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no request name given"); + validate_identifier(&ctx->loc, name, STANDALONE_IDENT); message = create_message(ctx->loc, name); if (strcmp(element_name, "request") == 0) @@ -748,6 +800,7 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no argument name given"); + validate_identifier(&ctx->loc, name, STANDALONE_IDENT); arg = create_arg(name); if (!set_arg_type(arg, type)) fail(&ctx->loc, "unknown type (%s)", type); @@ -757,8 +810,12 @@ start_element(void *data, const char *element_name, const char **atts) ctx->message->new_id_count++; /* fallthrough */ case OBJECT: - if (interface_name) + if (interface_name) { + validate_identifier(&ctx->loc, + interface_name, + STANDALONE_IDENT); arg->interface_name = xstrdup(interface_name); + } break; default: if (interface_name != NULL) @@ -793,6 +850,7 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no enum name given"); + validate_identifier(&ctx->loc, name, TRAILING_IDENT); enumeration = create_enumeration(name); if (bitfield == NULL || strcmp(bitfield, "false") == 0) @@ -812,6 +870,7 @@ start_element(void *data, const char *element_name, const char **atts) if (name == NULL) fail(&ctx->loc, "no entry name given"); + validate_identifier(&ctx->loc, name, TRAILING_IDENT); entry = create_entry(name, value); version = version_from_since(ctx, since); From 6db761d16229084e576848967402d30b656e2dbf Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 13 Apr 2019 18:33:06 -0400 Subject: [PATCH 0585/1152] tests: Verify that wayland_scanner can catch bad identifiers The test runs wayland_scanner on a set of XML protocol files which have malformed element names, and confirms that an error is produced and indicates the correct line. Copyright notifications are not included in the test files, as they are not code; of course, the project license still applies. Signed-off-by: Manuel Stoeckl --- Makefile.am | 7 +++++++ tests/data/bad-identifier-arg.xml | 10 ++++++++++ tests/data/bad-identifier-entry.xml | 11 +++++++++++ tests/data/bad-identifier-enum.xml | 10 ++++++++++ tests/data/bad-identifier-event.xml | 8 ++++++++ tests/data/bad-identifier-interface.xml | 8 ++++++++ tests/data/bad-identifier-protocol.xml | 8 ++++++++ tests/data/bad-identifier-request.xml | 10 ++++++++++ tests/scanner-test.sh | 23 +++++++++++++++++++++++ 9 files changed, 95 insertions(+) create mode 100644 tests/data/bad-identifier-arg.xml create mode 100644 tests/data/bad-identifier-entry.xml create mode 100644 tests/data/bad-identifier-enum.xml create mode 100644 tests/data/bad-identifier-event.xml create mode 100644 tests/data/bad-identifier-interface.xml create mode 100644 tests/data/bad-identifier-protocol.xml create mode 100644 tests/data/bad-identifier-request.xml diff --git a/Makefile.am b/Makefile.am index 489f5818..a41f959c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -291,6 +291,13 @@ exec_fd_leak_checker_LDADD = libtest-helpers.la EXTRA_DIST += tests/scanner-test.sh \ protocol/tests.xml \ + tests/data/bad-identifier-arg.xml \ + tests/data/bad-identifier-entry.xml \ + tests/data/bad-identifier-enum.xml \ + tests/data/bad-identifier-event.xml \ + tests/data/bad-identifier-interface.xml \ + tests/data/bad-identifier-protocol.xml \ + tests/data/bad-identifier-request.xml \ tests/data/example.xml \ tests/data/example-client.h \ tests/data/example-server.h \ diff --git a/tests/data/bad-identifier-arg.xml b/tests/data/bad-identifier-arg.xml new file mode 100644 index 00000000..ac2a6b76 --- /dev/null +++ b/tests/data/bad-identifier-arg.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/data/bad-identifier-entry.xml b/tests/data/bad-identifier-entry.xml new file mode 100644 index 00000000..6ea2fae0 --- /dev/null +++ b/tests/data/bad-identifier-entry.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/data/bad-identifier-enum.xml b/tests/data/bad-identifier-enum.xml new file mode 100644 index 00000000..3225384e --- /dev/null +++ b/tests/data/bad-identifier-enum.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/data/bad-identifier-event.xml b/tests/data/bad-identifier-event.xml new file mode 100644 index 00000000..9708e3bc --- /dev/null +++ b/tests/data/bad-identifier-event.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/data/bad-identifier-interface.xml b/tests/data/bad-identifier-interface.xml new file mode 100644 index 00000000..17404c5e --- /dev/null +++ b/tests/data/bad-identifier-interface.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/data/bad-identifier-protocol.xml b/tests/data/bad-identifier-protocol.xml new file mode 100644 index 00000000..7a172045 --- /dev/null +++ b/tests/data/bad-identifier-protocol.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/data/bad-identifier-request.xml b/tests/data/bad-identifier-request.xml new file mode 100644 index 00000000..a68c8aac --- /dev/null +++ b/tests/data/bad-identifier-request.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/scanner-test.sh b/tests/scanner-test.sh index ff250894..35ba0473 100755 --- a/tests/scanner-test.sh +++ b/tests/scanner-test.sh @@ -36,6 +36,20 @@ generate_and_compare() { fail "$2 -> $3" } +verify_error() { + echo + echo "Checking that reading $1 gives an error on line $3" + + [ -f "$TEST_DATA_DIR/$1" ] || hard_fail "$1 not present" + + # Confirm failure error code + "$WAYLAND_SCANNER" server-header < "$TEST_DATA_DIR/$1" >/dev/null 2>"$TEST_OUTPUT_DIR/$2" && \ + fail "$1 return code check" + + # Verify that an error is produced at the correct line + grep -q ":$3: error:" "$TEST_OUTPUT_DIR/$2" && echo "$1 PASS" || fail "$1 line number check" +} + generate_and_compare "code" "example.xml" "example-code.c" generate_and_compare "client-header" "example.xml" "example-client.h" generate_and_compare "server-header" "example.xml" "example-server.h" @@ -52,4 +66,13 @@ generate_and_compare "-c server-header" "small.xml" "small-server-core.h" generate_and_compare "code" "small.xml" "small-code.c" generate_and_compare "public-code" "small.xml" "small-code.c" generate_and_compare "private-code" "small.xml" "small-private-code.c" + +verify_error "bad-identifier-arg.xml" "bad-identifier-arg.log" 7 +verify_error "bad-identifier-entry.xml" "bad-identifier-entry.log" 8 +verify_error "bad-identifier-enum.xml" "bad-identifier-enum.log" 6 +verify_error "bad-identifier-event.xml" "bad-identifier-event.log" 6 +verify_error "bad-identifier-interface.xml" "bad-identifier-interface.log" 3 +verify_error "bad-identifier-protocol.xml" "bad-identifier-protocol.log" 2 +verify_error "bad-identifier-request.xml" "bad-identifier-request.log" 6 + exit $RETCODE From 294ed97e646a41b7749cd67e240138fcab5bdc5a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 26 Apr 2019 22:40:18 +0200 Subject: [PATCH 0586/1152] log: remove "%m" from format strings by using strerror(errno) The printf() format specifier "%m" is a glibc extension to print the string returned by strerror(errno). While supported by other libraries (e.g. uClibc and musl), it is not widely portable. In Wayland code the format string is often passed to a logging function that calls other syscalls before the conversion of "%m" takes place. If one of such syscall modifies the value in errno, the conversion of "%m" will incorrectly report the error string corresponding to the new value of errno. Remove all the occurrences of the specifier "%m" in Wayland code by using directly the string returned by strerror(errno). Signed-off-by: Antonio Borneo --- src/event-loop.c | 4 ++-- src/scanner.c | 2 +- src/wayland-server.c | 6 +++--- src/wayland-shm.c | 4 +++- tests/test-runner.c | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index eb2dce63..54c8474a 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -231,7 +231,7 @@ wl_event_source_timer_dispatch(struct wl_event_source *source, len = read(source->fd, &expires, sizeof expires); if (!(len == -1 && errno == EAGAIN) && len != sizeof expires) /* Is there anything we can do here? Will this ever happen? */ - wl_log("timerfd read error: %m\n"); + wl_log("timerfd read error: %s\n", strerror(errno)); return timer_source->func(timer_source->base.data); } @@ -325,7 +325,7 @@ wl_event_source_signal_dispatch(struct wl_event_source *source, len = read(source->fd, &signal_info, sizeof signal_info); if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info) /* Is there anything we can do here? Will this ever happen? */ - wl_log("signalfd read error: %m\n"); + wl_log("signalfd read error: %s\n", strerror(errno)); return signal_source->func(signal_source->signal_number, signal_source->base.data); diff --git a/src/scanner.c b/src/scanner.c index 86d90c0a..8cffea56 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -2015,7 +2015,7 @@ int main(int argc, char *argv[]) buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE); len = fread(buf, 1, XML_BUFFER_SIZE, input); if (len < 0) { - fprintf(stderr, "fread: %m\n"); + fprintf(stderr, "fread: %s\n", strerror(errno)); fclose(input); exit(EXIT_FAILURE); } diff --git a/src/wayland-server.c b/src/wayland-server.c index 19f6a760..884a5a3f 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1362,7 +1362,7 @@ socket_data(int fd, uint32_t mask, void *data) client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name, &length); if (client_fd < 0) - wl_log("failed to accept: %m\n"); + wl_log("failed to accept: %s\n", strerror(errno)); else if (!wl_client_create(display, client_fd)) close(client_fd); @@ -1467,12 +1467,12 @@ _wl_display_add_socket(struct wl_display *display, struct wl_socket *s) size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path); if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) { - wl_log("bind() failed with error: %m\n"); + wl_log("bind() failed with error: %s\n", strerror(errno)); return -1; } if (listen(s->fd, 128) < 0) { - wl_log("listen() failed with error: %m\n"); + wl_log("listen() failed with error: %s\n", strerror(errno)); return -1; } diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 4191231d..967b8759 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "wayland-util.h" #include "wayland-private.h" @@ -281,7 +282,8 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, if (pool->data == MAP_FAILED) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, - "failed mmap fd %d: %m", fd); + "failed mmap fd %d: %s", fd, + strerror(errno)); goto err_free; } close(fd); diff --git a/tests/test-runner.c b/tests/test-runner.c index 1487dc48..8f084458 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -338,7 +338,8 @@ int main(int argc, char *argv[]) if (waitid(P_PID, pid, &info, WEXITED)) { stderr_set_color(RED); - fprintf(stderr, "waitid failed: %m\n"); + fprintf(stderr, "waitid failed: %s\n", + strerror(errno)); stderr_reset_color(); abort(); From 2485a5c2749f636371b91c3f71c74d2d223d0020 Mon Sep 17 00:00:00 2001 From: orbea Date: Fri, 31 May 2019 08:09:35 -0700 Subject: [PATCH 0587/1152] Add a missing -pthread to fix compile with slibtool. When compiling wayland with slibtool instead of GNU libtool it will fail building libtest_runner with an undefined reference to pthread_join@@GLIBC_2.2.5. This is because -pthread (Or -lpthread) is missing from display_test. If its added the build succeeds as expected with slibtool and continues to work with libtool. Its likely that libtool is hiding this failure by silently adding the missing flag which is not uncommon... Exposed in commit aa51a833eb9b3d8fb58a64ff685b249d65ec35b5. Fixes https://gitlab.freedesktop.org/wayland/wayland/issues/91 Signed-off-by: orbea --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index a41f959c..a0b11d5e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -233,6 +233,7 @@ array_test_SOURCES = tests/array-test.c array_test_LDADD = libtest-runner.la client_test_SOURCES = tests/client-test.c client_test_LDADD = libtest-runner.la +display_test_CFLAGS = -pthread display_test_SOURCES = tests/display-test.c display_test_LDADD = libtest-runner.la nodist_display_test_SOURCES = \ From 55d044810ca32ae24499d2c6aee6084d7e31d576 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sat, 1 Jun 2019 15:11:48 -0700 Subject: [PATCH 0588/1152] Use wl_container_of internally Rather than have two versions of the macro with slightly different interfaces, just use wl_container_of internally. This also removes use of statement expressions, a GNU C extension. Signed-off-by: Michael Forney --- src/event-loop.c | 4 ++-- src/wayland-client.c | 7 +++---- src/wayland-private.h | 4 ---- src/wayland-server.c | 4 +++- tests/client-test.c | 2 +- tests/display-test.c | 2 +- tests/event-loop-test.c | 2 +- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index 54c8474a..017ab27c 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -595,8 +595,8 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop) struct wl_event_source_idle *source; while (!wl_list_empty(&loop->idle_list)) { - source = container_of(loop->idle_list.next, - struct wl_event_source_idle, base.link); + source = wl_container_of(loop->idle_list.next, + source, base.link); source->func(source->base.data); wl_event_source_remove(&source->base); } diff --git a/src/wayland-client.c b/src/wayland-client.c index b0805f14..38756f19 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -298,8 +298,8 @@ wl_event_queue_release(struct wl_event_queue *queue) struct wl_closure *closure; while (!wl_list_empty(&queue->event_list)) { - closure = container_of(queue->event_list.next, - struct wl_closure, link); + closure = wl_container_of(queue->event_list.next, + closure, link); wl_list_remove(&closure->link); destroy_queued_closure(closure); } @@ -1400,8 +1400,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) int opcode; bool proxy_destroyed; - closure = container_of(queue->event_list.next, - struct wl_closure, link); + closure = wl_container_of(queue->event_list.next, closure, link); wl_list_remove(&closure->link); opcode = closure->opcode; diff --git a/src/wayland-private.h b/src/wayland-private.h index 29516ec9..8a97fabf 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -42,10 +42,6 @@ #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) -#define container_of(ptr, type, member) ({ \ - const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - #define WL_MAP_SERVER_SIDE 0 #define WL_MAP_CLIENT_SIDE 1 #define WL_SERVER_ID_START 0xff000000 diff --git a/src/wayland-server.c b/src/wayland-server.c index 884a5a3f..83b984f5 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1899,7 +1899,9 @@ wl_client_get_link(struct wl_client *client) WL_EXPORT struct wl_client * wl_client_from_link(struct wl_list *link) { - return container_of(link, struct wl_client, link); + struct wl_client *client; + + return wl_container_of(link, client, link); } /** Add a listener for the client's resource creation signal diff --git a/tests/client-test.c b/tests/client-test.c index 2e332f81..960cfa95 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -47,7 +47,7 @@ static void client_destroy_notify(struct wl_listener *l, void *data) { struct client_destroy_listener *listener = - container_of(l, struct client_destroy_listener, listener); + wl_container_of(l, listener, listener); listener->done = 1; } diff --git a/tests/display-test.c b/tests/display-test.c index 6d98cc77..74a24f18 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -60,7 +60,7 @@ display_destroy_notify(struct wl_listener *l, void *data) { struct display_destroy_listener *listener; - listener = container_of(l, struct display_destroy_listener, listener); + listener = wl_container_of(l, listener, listener); listener->done = 1; } diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index 33566b41..9659815b 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -339,7 +339,7 @@ static void event_loop_destroy_notify(struct wl_listener *l, void *data) { struct event_loop_destroy_listener *listener = - container_of(l, struct event_loop_destroy_listener, listener); + wl_container_of(l, listener, listener); listener->done = 1; } From 678c8681e28739da1fea667ae59118cfc0968497 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sat, 1 Jun 2019 15:01:23 -0700 Subject: [PATCH 0589/1152] Avoid pointer arithmetic on `void *` The pointer operand to the binary `+` operator must be to a complete object type. Since we are working with byte sizes, use `char *` for arithmetic instead. Signed-off-by: Michael Forney --- src/wayland-util.c | 2 +- tests/array-test.c | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 3a471a88..d5973bf1 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -131,7 +131,7 @@ wl_array_add(struct wl_array *array, size_t size) array->alloc = alloc; } - p = array->data + array->size; + p = (char *)array->data + array->size; array->size += size; return p; diff --git a/tests/array-test.c b/tests/array-test.c index eda610b5..78dfbb0a 100644 --- a/tests/array-test.c +++ b/tests/array-test.c @@ -87,8 +87,7 @@ TEST(array_add) /* verify the data */ for (i = 0; i < iterations; ++i) { - const int index = datasize * i; - struct mydata* check = (struct mydata*)(array.data + index); + struct mydata* check = (struct mydata*)array.data + i; assert(check->a == i * 3); assert(check->b == 20000 - i); @@ -121,9 +120,8 @@ TEST(array_copy) /* check the copy */ for (i = 0; i < iterations; i++) { - const int index = sizeof(int) * i; - int *s = (int *)(source.data + index); - int *c = (int *)(copy.data + index); + int *s = (int *)source.data + i; + int *c = (int *)copy.data + i; assert(*s == *c); /* verify the values are the same */ assert(s != c); /* ensure the addresses aren't the same */ From 6dbf9f72b686f741d0b210d97813f400ca762475 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Fri, 5 Jul 2019 19:42:16 -0400 Subject: [PATCH 0590/1152] protocol: clarify wl_display.delete_id description libwayland-server only sends wl_display.delete_id events when it responds to a client's destruction of a client-allocated object. server-allocated objects are silently removed, as per `wl_resource_destroy`. Signed-off-by: Manuel Stoeckl --- protocol/wayland.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index dee0ac10..d1b28be7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -101,10 +101,10 @@ This event is used internally by the object ID management - logic. When a client deletes an object, the server will send - this event to acknowledge that it has seen the delete request. - When the client receives this event, it will know that it can - safely reuse the object ID. + logic. When a client deletes an object that it had created, + the server will send this event to acknowledge that it has + seen the delete request. When the client receives this event, + it will know that it can safely reuse the object ID. From a281783339f7be4d5b6a65c2ba0a6d70ed6d0f1d Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Mon, 13 May 2019 21:40:12 +1200 Subject: [PATCH 0591/1152] wayland.xml: Make releases for multiple 'wl_surface.attach' undefined Fixes #46 The way wl_buffer is specified makes this situation inherently racy, meaning there is no way this can be done unambiguously. Current real compositor implementations already have differing behaviour for this, so any client relying on it was already broken, if any such client exists. This specifically only singles out wl_buffer.release as being undefined; every other aspect of it should still be valid. This is so existing and correct uses of multiple attaches are still valid, where a "static"/immutable wl_buffer is being used (i.e. they don't care about the release event). Signed-off-by: Scott Anderson --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d1b28be7..50fe381c 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1368,6 +1368,12 @@ will not receive a release event, and is not used by the compositor. + If a pending wl_buffer has been committed to more than one wl_surface, + the delivery of wl_buffer.release events becomes undefined. A well + behaved client should not rely on wl_buffer.release events in this + case. Alternatively, a client could create multiple wl_buffer objects + from the same backing storage or use wp_linux_buffer_release. + Destroying the wl_buffer after wl_buffer.release does not change the surface contents. However, if the client destroys the wl_buffer before receiving the wl_buffer.release event, the surface From 9d63c9ff84af8187b947c5eabb98b87421bce7f9 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Fri, 5 Jul 2019 19:48:18 -0400 Subject: [PATCH 0592/1152] connection: do not abort when dup(fd) fails Instead, cleanly exit wl_closure_marshal and let the caller handler the error. For wayland-client, the sole calling function will call wl_abort() anyway. For wayland-server, the calling function will cleanly shutdown the client. This change ensures that compositors run with low file descriptor limits or internal leaks need not crash suddenly (and sometimes far from the problem) when space runs out. Signed-off-by: Manuel Stoeckl --- src/connection.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index 7fba999b..d0c7d9fc 100644 --- a/src/connection.c +++ b/src/connection.c @@ -644,8 +644,12 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, case 'h': fd = args[i].h; dup_fd = wl_os_dupfd_cloexec(fd, 0); - if (dup_fd < 0) - wl_abort("dup failed: %s\n", strerror(errno)); + if (dup_fd < 0) { + wl_closure_destroy(closure); + wl_log("error marshalling arguments for %s: dup failed: %s\n", + message->name, strerror(errno)); + return NULL; + } closure->args[i].h = dup_fd; break; default: From 6908c8c85a2e33e5654f64a55cd4f847bf385cae Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 16 Feb 2019 16:06:52 +0100 Subject: [PATCH 0593/1152] cursor: Use memfd_create() when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This (so-far) Linux-only API lets users create file descriptors purely in memory, without any backing file on the filesystem and the race condition which could ensue when unlink()ing it. It also allows seals to be placed on the file, ensuring to every other process that we won’t be allowed to shrink the contents, potentially causing a SIGBUS when they try reading it. This patch is best viewed with the -w option of git log -p. Signed-off-by: Emmanuel Gil Peyrot Reviewed-by: Simon Ser --- configure.ac | 2 +- cursor/os-compatibility.c | 64 +++++++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 59ae244b..c332107f 100644 --- a/configure.ac +++ b/configure.ac @@ -63,7 +63,7 @@ fi AC_SUBST(GCC_CFLAGS) AC_CHECK_HEADERS([sys/prctl.h]) -AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl]) +AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl memfd_create]) # *BSD don't have libdl, but they have its functions in libc WESTON_SEARCH_LIBS([DL], [dl], [dlsym]) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index e972d219..9008755d 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -25,6 +25,8 @@ #define _GNU_SOURCE +#include "config.h" + #include #include #include @@ -32,7 +34,10 @@ #include #include -#include "config.h" +#ifdef HAVE_MEMFD_CREATE +#include +#endif + #include "os-compatibility.h" #ifndef HAVE_MKOSTEMP @@ -99,6 +104,13 @@ create_tmpfile_cloexec(char *tmpname) * given size. If disk space is insufficent, errno is set to ENOSPC. * If posix_fallocate() is not supported, program may receive * SIGBUS on accessing mmap()'ed file contents instead. + * + * If the C library implements memfd_create(), it is used to create the + * file purely in memory, without any backing file name on the file + * system, and then sealing off the possibility of shrinking it. This + * can then be checked before accessing mmap()'ed file contents, to + * make sure SIGBUS can't happen. It also avoids requiring + * XDG_RUNTIME_DIR. */ int os_create_anonymous_file(off_t size) @@ -109,26 +121,40 @@ os_create_anonymous_file(off_t size) int fd; int ret; - path = getenv("XDG_RUNTIME_DIR"); - if (!path) { - errno = ENOENT; - return -1; +#ifdef HAVE_MEMFD_CREATE + fd = memfd_create("wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd >= 0) { + /* We can add this seal before calling posix_fallocate(), as + * the file is currently zero-sized anyway. + * + * There is also no need to check for the return value, we + * couldn't do anything with it anyway. + */ + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); + } else +#endif + { + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + if (!name) + return -1; + + strcpy(name, path); + strcat(name, template); + + fd = create_tmpfile_cloexec(name); + + free(name); + + if (fd < 0) + return -1; } - name = malloc(strlen(path) + sizeof(template)); - if (!name) - return -1; - - strcpy(name, path); - strcat(name, template); - - fd = create_tmpfile_cloexec(name); - - free(name); - - if (fd < 0) - return -1; - #ifdef HAVE_POSIX_FALLOCATE ret = posix_fallocate(fd, 0, size); if (ret != 0) { From 493ab79bd2cdf8f9f12fb9e5522200dc668b85e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 10 Jul 2019 09:13:33 +0200 Subject: [PATCH 0594/1152] proxy: Add API to tag proxy objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an application and a toolkit share the same Wayland connection, it will receive events with each others objects. For example if the toolkit manages a set of surfaces, and the application another set, if both the toolkit and application listen to pointer focus events, they'll receive focus events for each others surfaces. In order for the toolkit and application layers to identify whether a surface is managed by itself or not, it cannot only rely on retrieving the proxy user data, without going through all it's own proxy objects finding whether it's one of them. By adding the ability to "tag" a proxy object, the toolkit and application can use the tag to identify what the user data pointer points to something known. To create a tag, the recommended way is to define a statically allocated constant char array containing some descriptive string. The tag will be the pointer to the non-const pointer to the beginning of the array. For example, to identify whether a focus event is for a surface managed by the code in question: static const char *my_tag = "my tag"; static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { struct window *window; const char * const *tag; tag = wl_proxy_get_tag((struct wl_proxy *) surface); if (tag != &my_tag) return; window = wl_surface_get_user_data(surface); ... } ... static void init_window_surface(struct window *window) { struct wl_surface *surface; surface = wl_compositor_create_surface(compositor); wl_surface_set_user_data(surface, window); wl_proxy_set_tag((struct wl_proxy *) surface, &my_tag); } Signed-off-by: Jonas Ådahl --- Makefile.am | 3 + src/wayland-client-core.h | 7 ++ src/wayland-client.c | 65 ++++++++++++++++++ tests/proxy-test.c | 136 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+) create mode 100644 tests/proxy-test.c diff --git a/Makefile.am b/Makefile.am index a0b11d5e..868910cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -174,6 +174,7 @@ built_test_programs = \ sanity-test \ socket-test \ queue-test \ + proxy-test \ signal-test \ newsignal-test \ resources-test \ @@ -258,6 +259,8 @@ socket_test_SOURCES = tests/socket-test.c socket_test_LDADD = libtest-runner.la queue_test_SOURCES = tests/queue-test.c queue_test_LDADD = libtest-runner.la +proxy_test_SOURCES = tests/proxy-test.c +proxy_test_LDADD = libtest-runner.la signal_test_SOURCES = tests/signal-test.c signal_test_LDADD = libtest-runner.la # wayland-server.c is needed here to access wl_priv_* functions diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 03e781b5..0cd96e01 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -191,6 +191,13 @@ wl_proxy_get_version(struct wl_proxy *proxy); uint32_t wl_proxy_get_id(struct wl_proxy *proxy); +void +wl_proxy_set_tag(struct wl_proxy *proxy, + const char * const *tag); + +const char * const * +wl_proxy_get_tag(struct wl_proxy *proxy); + const char * wl_proxy_get_class(struct wl_proxy *proxy); diff --git a/src/wayland-client.c b/src/wayland-client.c index 38756f19..0821af1f 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -69,6 +69,7 @@ struct wl_proxy { void *user_data; wl_dispatcher_func_t dispatcher; uint32_t version; + const char * const *tag; }; struct wl_event_queue { @@ -2059,6 +2060,70 @@ wl_proxy_get_id(struct wl_proxy *proxy) return proxy->object.id; } +/** Set the tag of a proxy object + * + * A toolkit or application can set a unique tag on a proxy in order to + * identify whether an object is managed by itself or some external part. + * + * To create a tag, the recommended way is to define a statically allocated + * constant char array containing some descriptive string. The tag will be the + * pointer to the non-const pointer to the beginning of the array. + * + * For example, to define and set a tag on a surface managed by a certain + * subsystem: + * + * static const char *my_tag = "my tag"; + * + * wl_proxy_set_tag((struct wl_proxy *) surface, &my_tag); + * + * Then, in a callback with wl_surface as an argument, in order to check + * whether it's a surface managed by the same subsystem. + * + * const char * const *tag; + * + * tag = wl_proxy_get_tag((struct wl_proxy *) surface); + * if (tag != &my_tag) + * return; + * + * ... + * + * For debugging purposes, a tag should be suitable to be included in a debug + * log entry, e.g. + * + * const char * const *tag; + * + * tag = wl_proxy_get_tag((struct wl_proxy *) surface); + * printf("Got a surface with the tag %p (%s)\n", + * tag, (tag && *tag) ? *tag : ""); + * + * \param proxy The proxy object + * \param tag The tag + * + * \memberof wl_proxy + * \since 1.17.90 + */ +WL_EXPORT void +wl_proxy_set_tag(struct wl_proxy *proxy, + const char * const *tag) +{ + proxy->tag = tag; +} + +/** Get the tag of a proxy object + * + * See wl_proxy_set_tag for details. + * + * \param proxy The proxy object + * + * \memberof wl_proxy + * \since 1.17.90 + */ +WL_EXPORT const char * const * +wl_proxy_get_tag(struct wl_proxy *proxy) +{ + return proxy->tag; +} + /** Get the interface name (class) of a proxy object * * \param proxy The proxy object diff --git a/tests/proxy-test.c b/tests/proxy-test.c new file mode 100644 index 00000000..d91a73d9 --- /dev/null +++ b/tests/proxy-test.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "wayland-server.h" +#include "wayland-client.h" +#include "test-runner.h" + +static struct { + struct wl_display *display; + struct wl_event_loop *loop; + int sync_count; +} server; + +static struct { + struct wl_display *display; + struct wl_callback *callback_a; + struct wl_callback *callback_b; + int callback_count; +} client; + +static const char *tag_a = "tag"; +static const char *tag_b = "tag"; + +static void +callback_done(void *data, struct wl_callback *cb, uint32_t time) +{ + const char * const *expected_tag; + const char * const *tag; + + if (cb == client.callback_a) + expected_tag = &tag_a; + else if (cb == client.callback_b) + expected_tag = &tag_b; + else + assert(!"unexpected callback"); + + tag = wl_proxy_get_tag((struct wl_proxy *) cb); + + assert(tag == expected_tag); + assert(strcmp(*tag, "tag") == 0); + + wl_callback_destroy(cb); + + client.callback_count++; +} + +static const struct wl_callback_listener callback_listener = { + callback_done, +}; + +static void +logger_func(void *user_data, + enum wl_protocol_logger_type type, + const struct wl_protocol_logger_message *message) +{ + if (type != WL_PROTOCOL_LOGGER_REQUEST) + return; + + assert(strcmp(wl_resource_get_class(message->resource), + "wl_display") == 0); + assert(strcmp(message->message->name, "sync") == 0); + + server.sync_count++; +} + +TEST(proxy_tag) +{ + const char *socket; + struct wl_protocol_logger *logger; + + assert(&tag_a != &tag_b); + + server.display = wl_display_create(); + assert(server.display); + server.loop = wl_display_get_event_loop(server.display); + assert(server.loop); + socket = wl_display_add_socket_auto(server.display); + assert(socket); + logger = wl_display_add_protocol_logger(server.display, + logger_func, NULL); + assert(logger); + + client.display = wl_display_connect(socket); + assert(client.display); + + client.callback_a = wl_display_sync(client.display); + wl_callback_add_listener(client.callback_a, &callback_listener, NULL); + wl_proxy_set_tag((struct wl_proxy *) client.callback_a, + &tag_a); + + client.callback_b = wl_display_sync(client.display); + wl_callback_add_listener(client.callback_b, &callback_listener, NULL); + wl_proxy_set_tag((struct wl_proxy *) client.callback_b, + &tag_b); + + wl_display_flush(client.display); + + while (server.sync_count < 2) { + wl_event_loop_dispatch(server.loop, -1); + wl_display_flush_clients(server.display); + } + + wl_display_dispatch(client.display); + + assert(client.callback_count == 2); + + wl_display_disconnect(client.display); + wl_event_loop_dispatch(server.loop, 100); + + wl_display_destroy(server.display); +} From a2f1343b7e7c8f0a548b13a3424b7660a9ec0000 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 29 Jul 2019 22:39:00 -0400 Subject: [PATCH 0595/1152] Document unusual wl_registry.bind new_id behavior When wayland-scanner encounters a new_id field with no corresponding interface name defined, instead of emitting a function whose signature lines up with the usual case (a uint32_t ID), it adds the interface name as a string and the version number so that the interface can be identified from the protcol message. Without docs, this was previously left for the interprid wire protocol implementor (e.g. me an hour ago) to discover when Wayland clients send them apparently bogus messages. I would have preferred if a different primitive type were used here (e.g. typed_new_id) to reflect the fact that the wire protocol is different, but I felt it unwise to add a new primitive to wayland.xml in $current_year. --- doc/publican/sources/Protocol.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index fedaaaba..69edd2cd 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -167,10 +167,10 @@ new_id - The 32-bit object ID. On requests, the client - decides the ID. The only events with new_id are - advertisements of globals, and the server will use IDs below - 0x10000. + The 32-bit object ID. Generally, the interface used for the new + object is inferred from the xml, but in the case where it's not + specified, a new_id is preceeded by a string specifying + the interface name, and a uint specifying the version. From 790dd9da16eb40e54b2dabe412dccdc5ea005b77 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 2 Aug 2019 17:25:05 -0400 Subject: [PATCH 0596/1152] Add .editorconfig This is copied from Weston --- .editorconfig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..e0fc8531 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = tab +indent_size = 8 +max_line_length = 80 + +[*.xml] +indent_style = space +indent_size = 2 +tab_width = 8 From 17e49ba8443d76f05df89c9663e3661af292a1a4 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 2 Aug 2019 17:17:32 -0400 Subject: [PATCH 0597/1152] Improve description of wl_surface The original text makes some assumptions about surfaces which may not be true and fails to capture some details which are important to the essential traits of a wl_surface. --- protocol/wayland.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 50fe381c..94d4222a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1279,8 +1279,10 @@ - A surface is a rectangular area that is displayed on the screen. - It has a location, size and pixel contents. + A surface is a rectangular area that may be displayed on zero + or more outputs, and shown any number of times at the compositor's + discretion. They can present wl_buffers, receive user input, and + define a local coordinate system. The size of a surface (and relative positions on it) is described in surface-local coordinates, which may differ from the buffer From 152c9ed968124c253f0be25b76c2a083a21af37e Mon Sep 17 00:00:00 2001 From: Liu Wenlong Date: Mon, 26 Aug 2019 17:08:22 +0800 Subject: [PATCH 0598/1152] server: Fix fake "Address already in use" error In the current workflow, socket file will be deleted if it already exists. However, if the socket file is a symbolic link and the file that it refers to doesn't exist, we will got "Address already in use" because bind() thinks the socket file exists and won't create it. Now, use lstat() to determine whether the socket file exists. Signed-off-by: Liu Wenlong --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 83b984f5..3bc6ed72 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1393,7 +1393,7 @@ wl_socket_lock(struct wl_socket *socket) goto err_fd; } - if (stat(socket->addr.sun_path, &socket_stat) < 0 ) { + if (lstat(socket->addr.sun_path, &socket_stat) < 0 ) { if (errno != ENOENT) { wl_log("did not manage to stat file %s\n", socket->addr.sun_path); From a277cc6d5238321a37951bd0a0448bb6ce0e115f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 28 Aug 2019 17:11:21 +0300 Subject: [PATCH 0599/1152] client: check event opcode in queue_event If the client binds to a global with an interface mismatch, it may receive an event from the server with an unknown opcode. See [1]. Instead of crashing, print a more useful debug message and close the connection. [1]: https://gitlab.freedesktop.org/wayland/wayland/issues/113 Signed-off-by: Simon Ser --- src/wayland-client.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 0821af1f..ed502819 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1364,6 +1364,12 @@ queue_event(struct wl_display *display, int len) return size; } + if (opcode >= proxy->object.interface->event_count) { + wl_log("interface '%s' has no event %u\n", + proxy->object.interface->name, opcode); + return -1; + } + message = &proxy->object.interface->events[opcode]; closure = wl_connection_demarshal(display->connection, size, &display->objects, message); From cd9b3ef0cd2d6b6c5a07e07759699956af77555d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Sep 2019 20:49:34 +0300 Subject: [PATCH 0600/1152] Update .editorconfig for Python This uses the idiomatic Python indentation rules. Signed-off-by: Simon Ser --- .editorconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.editorconfig b/.editorconfig index e0fc8531..803abf34 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,3 +13,7 @@ max_line_length = 80 indent_style = space indent_size = 2 tab_width = 8 + +[*.py] +indent_style = space +indent_size = 4 From 8854f64baeec50ebb0fe5af748574c290cce0682 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Sep 2019 20:51:02 +0300 Subject: [PATCH 0601/1152] Add an automated script to update wl_shm.format This prevents mismatches and missing formats between wl_shm.formats and drm_fourcc.h. The script collects DRM_FORMAT_* constants from drm_fourcc.h, compares the list with the current wayland.xml entries (checking for any mismatch) and then appends missing entries to wayland.xml. Enum values are obtained by executing a generated C file which prints the constants. There is no other reliable way to get these values as they are defined via various macros. There is no widespread Python library able to parse an XML file and format it with all whitespace preserved. For this reason, we don't use an XML library to create the new XML elements. Instead, we keep track of the line number of the last wl_shm.format enum entry and add new entries right after. To be able to read the line number of an element, we use lxml (the standard library doesn't retain line number information). Signed-off-by: Simon Ser --- protocol/generate-shm-formats.py | 153 +++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100755 protocol/generate-shm-formats.py diff --git a/protocol/generate-shm-formats.py b/protocol/generate-shm-formats.py new file mode 100755 index 00000000..c56642e1 --- /dev/null +++ b/protocol/generate-shm-formats.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +# This script synchronizes wayland.xml's wl_shm.format enum with drm_fourcc.h. +# Invoke it to update wayland.xml, then manually check the changes applied. +# +# Requires Python 3, python-lxml, a C compiler and pkg-config. + +import os +import subprocess +import sys +import tempfile +# We need lxml instead of the standard library because we want +# Element.sourceline +from lxml import etree as ElementTree + +proto_dir = os.path.dirname(os.path.realpath(__file__)) +wayland_proto = proto_dir + "/wayland.xml" + +cc = os.getenv("CC", "cc") +pkg_config = os.getenv("PKG_CONFIG", "pkg-config") + +# Find drm_fourcc.h +version = subprocess.check_output([pkg_config, "libdrm", + "--modversion"]).decode().strip() +cflags = subprocess.check_output([pkg_config, "libdrm", + "--cflags-only-I"]).decode().strip().split() +libdrm_include = None +for include_flag in cflags: + if not include_flag.startswith("-I"): + raise Exception("Expected one include dir for libdrm") + include_dir = include_flag[2:] + if include_dir.endswith("/libdrm"): + libdrm_include = include_dir + fourcc_include = libdrm_include + "/drm_fourcc.h" +if libdrm_include == None: + raise Exception("Failed to find libdrm include dir") + +print("Using libdrm " + version, file=sys.stderr) + +def drm_format_to_wl(ident): + return ident.replace("DRM_FORMAT_", "").lower() + +# Collect DRM format constant names +ident_list = [] +descriptions = {} +prev_comment = None +with open(fourcc_include) as input_file: + for l in input_file.readlines(): + l = l.strip() + + # Collect comments right before format definitions + if l.startswith("/*") and l.endswith("*/"): + prev_comment = l[2:-2] + continue + desc = prev_comment + prev_comment = None + + # Recognize format definitions + parts = l.split() + if len(parts) < 3 or parts[0] != "#define": + continue + ident = parts[1] + if not ident.startswith("DRM_FORMAT_") or ident.startswith( + "DRM_FORMAT_MOD_"): + continue + + ident_list.append(ident) + + # Prefer in-line comments + if l.endswith("*/"): + desc = l[l.rfind("/*") + 2:-2] + if desc != None: + descriptions[drm_format_to_wl(ident)] = desc.strip() + +# Collect DRM format values +idents = {} +with tempfile.TemporaryDirectory() as work_dir: + c_file_name = work_dir + "/print-formats.c" + exe_file_name = work_dir + "/print-formats" + + with open(c_file_name, "w+") as c_file: + c_file.write('#include \n') + c_file.write('#include \n') + c_file.write('#include \n') + c_file.write('#include \n') + c_file.write('\n') + c_file.write('int main(void) {\n') + for ident in ident_list: + c_file.write('printf("0x%" PRIX64 "\\n", (uint64_t)' + ident + ');\n') + c_file.write('}\n') + + subprocess.check_call([cc, "-Wall", "-Wextra", "-o", exe_file_name, + c_file_name] + cflags) + output = subprocess.check_output([exe_file_name]).decode().strip() + for i, val in enumerate(output.splitlines()): + idents[ident_list[i]] = val + +# We don't need those +del idents["DRM_FORMAT_BIG_ENDIAN"] +del idents["DRM_FORMAT_INVALID"] +del idents["DRM_FORMAT_RESERVED"] + +# Convert from DRM constants to Wayland wl_shm.format entries +formats = {} +for ident, val in idents.items(): + formats[drm_format_to_wl(ident)] = val.lower() +# Special case for ARGB8888 and XRGB8888 +formats["argb8888"] = "0" +formats["xrgb8888"] = "1" + +print("Loaded {} formats from drm_fourcc.h".format(len(formats)), file=sys.stderr) + +tree = ElementTree.parse("wayland.xml") +root = tree.getroot() +wl_shm_format = root.find("./interface[@name='wl_shm']/enum[@name='format']") +if wl_shm_format == None: + raise Exception("wl_shm.format not found in wayland.xml") + +# Remove formats we already know about +last_line = None +for node in wl_shm_format: + if node.tag != "entry": + continue + fmt = node.attrib["name"] + val = node.attrib["value"] + if fmt not in formats: + raise Exception("Format present in wl_shm.formats but not in " + "drm_fourcc.h: " + fmt) + if val != formats[fmt]: + raise Exception("Format value in wl_shm.formats ({}) differs " + "from value in drm_fourcc.h ({}) for format {}" + .format(val, formats[fmt], fmt)) + del formats[fmt] + last_line = node.sourceline +if last_line == None: + raise Exception("Expected at least one existing wl_shm.format entry") + +print("Adding {} formats to wayland.xml...".format(len(formats)), file=sys.stderr) + +# Append new formats +new_wayland_proto = wayland_proto + ".new" +with open(new_wayland_proto, "w+") as output_file, \ + open(wayland_proto) as input_file: + for i, l in enumerate(input_file.readlines()): + output_file.write(l) + if i + 1 == last_line: + for fmt, val in formats.items(): + output_file.write(' \n') +os.rename(new_wayland_proto, wayland_proto) From e771ca91d76f2d35ed8fc65479666d2b0ac27ae8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Sep 2019 20:57:08 +0300 Subject: [PATCH 0602/1152] protocol: add a comment about the wl_shm.format script Add a comment to wl_shm.format to advise contributors to use the automated script (generate-shm-formats.py) instead of updating the list manually. Signed-off-by: Simon Ser --- protocol/wayland.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 94d4222a..0833e2e7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -293,10 +293,12 @@ formats are optional and may not be supported by the particular renderer in use. - The drm format codes match the macros defined in drm_fourcc.h. - The formats actually supported by the compositor will be - reported by the format event. + The drm format codes match the macros defined in drm_fourcc.h, except + argb8888 and xrgb8888. The formats actually supported by the compositor + will be reported by the format event. + From b69e547fa44e99f5d802ffb301027432b38005b8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Sep 2019 20:58:33 +0300 Subject: [PATCH 0603/1152] protocol: sync wl_shm.format with libdrm 2.4.99 This adds 42 new formats. Signed-off-by: Simon Ser --- protocol/wayland.xml | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 0833e2e7..e8973022 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -357,6 +357,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e18e3e195b0f3984d41de5850da1691638a414df Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 28 Aug 2019 17:26:52 +0300 Subject: [PATCH 0604/1152] server: check global interface on bind The interface name provided by the client isn't used at all. Check it matches the global's interface name to prevent object interface mismatches between the client and the server. These are especially easy to get when mixing up global names and other IDs in the client. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/issues/113 --- src/wayland-server.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 3bc6ed72..11cb7f57 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -917,6 +917,12 @@ registry_bind(struct wl_client *client, wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid global %s (%d)", interface, name); + else if (strcmp(global->interface->name, interface) != 0) + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid interface for global %u: " + "have %s, wanted %s", + name, interface, global->interface->name); else if (version == 0) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, From 6e5cedc20ad65d6784156bbc175f56557bd57c44 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Sep 2019 14:38:53 +0300 Subject: [PATCH 0605/1152] tests: test that binding to a global with an interface mismatch fails This test creates a wl_seat global, then tries to bind to it with the wl_output interface. Signed-off-by: Simon Ser --- tests/display-test.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index 74a24f18..a8e11f1d 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1355,3 +1355,70 @@ TEST(zombie_fd_errant_consumption) display_destroy(d); } + + +static void +registry_bind_interface_mismatch_handle_global(void *data, + struct wl_registry *registry, + uint32_t id, const char *intf, + uint32_t ver) +{ + uint32_t *seat_id_ptr = data; + + if (strcmp(intf, wl_seat_interface.name) == 0) { + *seat_id_ptr = id; + } +} + +static const struct wl_registry_listener bind_interface_mismatch_registry_listener = { + registry_bind_interface_mismatch_handle_global, + NULL +}; + +static void +registry_bind_interface_mismatch_client(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + uint32_t seat_id = 0; + void *ptr; + int ret; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, + &bind_interface_mismatch_registry_listener, + &seat_id); + + ret = wl_display_roundtrip(c->wl_display); + assert(ret >= 0); + assert(seat_id != 0); + + /* Bind with a different interface */ + ptr = wl_registry_bind(registry, seat_id, &wl_output_interface, 1); + ret = wl_display_roundtrip(c->wl_display); + assert(ret < 0); + check_bind_error(c); + + wl_proxy_destroy((struct wl_proxy *) ptr); + wl_registry_destroy(registry); + + client_disconnect_nocheck(c); +} + +TEST(registry_bind_interface_mismatch) +{ + struct display *d; + struct wl_global *seat_global; + + d = display_create(); + + seat_global = wl_global_create(d->wl_display, &wl_seat_interface, + 1, NULL, NULL); + + client_create_noarg(d, registry_bind_interface_mismatch_client); + display_run(d); + + wl_global_destroy(seat_global); + + display_destroy(d); +} From 4c2b7375612cd2eb8565898f76fb5e171b17777b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 11 Jul 2019 20:03:55 +0300 Subject: [PATCH 0606/1152] protocol: invalid_method is sent on malformed request Currently libwayland sends a wl_display.invalid_method when arguments provided with a request are invalid (e.g. too short, see wl_client_connection_data). Clarify the protocol by adding that invalid_method can be sent on malformed request. Signed-off-by: Simon Ser --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index e8973022..f1a13b75 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -91,7 +91,7 @@ + summary="method doesn't exist on the specified interface or malformed request"/> Date: Sat, 13 Jul 2019 17:33:49 -0400 Subject: [PATCH 0607/1152] client: Ignore new requests if display has a fatal error Once there has been a fatal display error, any new object requests potentially rely on invalid state. (For example, a failure to read from the compositor could hide a important event.) The safest way to handle the new requests is not to make them. Proxies produced by the request are still created, to ensure that any code using the library does not crash from an unexpected NULL pointer. Signed-off-by: Manuel Stoeckl --- src/wayland-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index ed502819..7c93c7b2 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -740,6 +740,10 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, goto err_unlock; } + if (proxy->display->last_error) { + goto err_unlock; + } + closure = wl_closure_marshal(&proxy->object, opcode, args, message); if (closure == NULL) wl_abort("Error marshalling request: %s\n", strerror(errno)); From 8a831ac6ec359c0dff67d2f4221fcd48a3a9a4ce Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 13 Jul 2019 17:54:14 -0400 Subject: [PATCH 0608/1152] client: Don't abort when sending a request fails Instead, set a fatal display error which will let an application using libwayland-client shutdown cleanly. Signed-off-by: Manuel Stoeckl --- src/wayland-client.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 7c93c7b2..53585000 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -745,14 +745,19 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, } closure = wl_closure_marshal(&proxy->object, opcode, args, message); - if (closure == NULL) - wl_abort("Error marshalling request: %s\n", strerror(errno)); + if (closure == NULL) { + wl_log("Error marshalling request: %s\n", strerror(errno)); + display_fatal_error(proxy->display, errno); + goto err_unlock; + } if (debug_client) wl_closure_print(closure, &proxy->object, true); - if (wl_closure_send(closure, proxy->display->connection)) - wl_abort("Error sending request: %s\n", strerror(errno)); + if (wl_closure_send(closure, proxy->display->connection)) { + wl_log("Error sending request: %s\n", strerror(errno)); + display_fatal_error(proxy->display, errno); + } wl_closure_destroy(closure); From a89a5349af690f87c24abcaafc524f2cfd6e9d24 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sun, 18 Aug 2019 12:36:14 -0400 Subject: [PATCH 0609/1152] tests: Test that send overflow doesn't abort The new display test runs a client that makes a very large number of trivial requests. After responding to initial setup requests, the server is paused, letting the trivial requests fill up the Unix socket buffer, making further writes to the socket fail. The test then checks that the client sets an appropriate error code, and does not abort or crash. Signed-off-by: Manuel Stoeckl --- tests/display-test.c | 65 +++++++++++++++++++++++++++++++++++++++++ tests/test-compositor.c | 26 ++++++++++++++--- tests/test-compositor.h | 1 + 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index a8e11f1d..cf571fac 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1422,3 +1422,68 @@ TEST(registry_bind_interface_mismatch) display_destroy(d); } + +static void +send_overflow_client(void *data) +{ + struct client *c = client_connect(); + int i, err = 0; + int *pipes = data; + char tmp = '\0'; + + /* On Linux, the Unix socket default buffer size is <=256KB, and + * each noop request requires 8 bytes; the buffer should thus + * overflow within about 32K /unhandled/ iterations */ + for (i = 0; i < 1000000; i++) { + noop_request(c); + err = wl_display_get_error(c->wl_display); + if (err) + break; + } + + /* Do not close the pipe file descriptors afterwards, because the leak + * check verifies that the initial/final FD counts are the same */ + assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp)); + + /* Expect an error */ + fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err)); + assert(err == EAGAIN); + + client_disconnect_nocheck(c); +} + +TEST(send_overflow_disconnection) +{ + struct display *d; + struct client_info *c; + char tmp; + int rpipe[2]; + int i; + + assert(pipe(rpipe) != -1); + + d = display_create(); + + c = client_create(d, send_overflow_client, &rpipe); + + /* Close write end of the pipe, so that the later read() call gets + * interrupted if the client dies */ + close(rpipe[1]); + + /* At least 2 loops of this are needed to respond for the client to + * set up the test interface */ + for (i = 0; i < 5; i++) { + wl_display_flush_clients(d->wl_display); + wl_event_loop_dispatch(wl_display_get_event_loop(d->wl_display), -1); + } + + /* Wait until all noop requests have been sent, or until client + * process aborts */ + (void)read(rpipe[0], &tmp, sizeof(tmp)); + close(rpipe[0]); + + /* For a clean shutdown */ + display_run(d); + + display_destroy(d); +} diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 72f63515..bd2b0156 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -45,7 +45,8 @@ struct test_compositor; static const struct wl_message tc_requests[] = { /* this request serves as a barrier for synchronizing*/ - { "stop_display", "u", NULL } + { "stop_display", "u", NULL }, + { "noop", "", NULL }, }; static const struct wl_message tc_events[] = { @@ -54,7 +55,7 @@ static const struct wl_message tc_events[] = { const struct wl_interface test_compositor_interface = { "test", 1, - 1, tc_requests, + 2, tc_requests, 1, tc_events }; @@ -62,6 +63,8 @@ struct test_compositor_interface { void (*stop_display)(struct wl_client *client, struct wl_resource *resource, uint32_t num); + void (*noop)(struct wl_client *client, + struct wl_resource *resource); }; struct test_compositor_listener { @@ -70,7 +73,8 @@ struct test_compositor_listener { }; enum { - STOP_DISPLAY = 0 + STOP_DISPLAY = 0, + TEST_NOOP = 1 }; enum { @@ -294,8 +298,16 @@ handle_stop_display(struct wl_client *client, wl_display_terminate(d->wl_display); } +static void +handle_noop(struct wl_client *client, struct wl_resource *resource) +{ + (void)client; + (void)resource; +} + static const struct test_compositor_interface tc_implementation = { - handle_stop_display + handle_stop_display, + handle_noop, }; static void @@ -509,3 +521,9 @@ stop_display(struct client *c, int num) return n; } + +void +noop_request(struct client *c) +{ + wl_proxy_marshal((struct wl_proxy *) c->tc, TEST_NOOP); +} diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 876d0c09..90999b2f 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -70,6 +70,7 @@ struct client { struct client *client_connect(void); void client_disconnect(struct client *); int stop_display(struct client *, int); +void noop_request(struct client *); /** * Usual workflow: From 9f004d8b0fa37787fe96662cf5ff414e8d6ef5e4 Mon Sep 17 00:00:00 2001 From: "Marty E. Plummer" Date: Sat, 11 May 2019 09:53:01 -0500 Subject: [PATCH 0610/1152] scanner: prepend protocol name to types symbol When doing unity builds via meson (example project: https://github.com/swaywm/sway) multiple source files are glued together via #include directives. Having every wayland-scanner generated source file have an identifier named '*types[]' will lead to errors in these unity builds if two or more of these are joined. Signed-off-by: Marty E. Plummer --- src/scanner.c | 10 +- tests/data/example-code.c | 240 ++++++++++++++++---------------- tests/data/small-code-core.c | 10 +- tests/data/small-code.c | 10 +- tests/data/small-private-code.c | 10 +- 5 files changed, 140 insertions(+), 140 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 8cffea56..7ed1ba1a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1722,7 +1722,7 @@ emit_types(struct protocol *protocol, struct wl_list *message_list) } static void -emit_messages(struct wl_list *message_list, +emit_messages(const char *name, struct wl_list *message_list, struct interface *interface, const char *suffix) { struct message *m; @@ -1775,7 +1775,7 @@ emit_messages(struct wl_list *message_list, break; } } - printf("\", types + %d },\n", m->type_index); + printf("\", %s_types + %d },\n", name, m->type_index); } printf("};\n\n"); @@ -1832,7 +1832,7 @@ emit_code(struct protocol *protocol, enum visibility vis) wl_array_release(&types); printf("\n"); - printf("static const struct wl_interface *types[] = {\n"); + printf("static const struct wl_interface *%s_types[] = {\n", protocol->name); emit_null_run(protocol); wl_list_for_each(i, &protocol->interface_list, link) { emit_types(protocol, &i->request_list); @@ -1842,8 +1842,8 @@ emit_code(struct protocol *protocol, enum visibility vis) wl_list_for_each_safe(i, next, &protocol->interface_list, link) { - emit_messages(&i->request_list, i, "requests"); - emit_messages(&i->event_list, i, "events"); + emit_messages(protocol->name, &i->request_list, i, "requests"); + emit_messages(protocol->name, &i->event_list, i, "events"); printf("%s const struct wl_interface " "%s_interface = {\n" diff --git a/tests/data/example-code.c b/tests/data/example-code.c index bc03fe56..2055c88e 100644 --- a/tests/data/example-code.c +++ b/tests/data/example-code.c @@ -48,7 +48,7 @@ extern const struct wl_interface wl_subsurface_interface; extern const struct wl_interface wl_surface_interface; extern const struct wl_interface wl_touch_interface; -static const struct wl_interface *types[] = { +static const struct wl_interface *wayland_types[] = { NULL, NULL, NULL, @@ -147,13 +147,13 @@ static const struct wl_interface *types[] = { }; static const struct wl_message wl_display_requests[] = { - { "sync", "n", types + 8 }, - { "get_registry", "n", types + 9 }, + { "sync", "n", wayland_types + 8 }, + { "get_registry", "n", wayland_types + 9 }, }; static const struct wl_message wl_display_events[] = { - { "error", "ous", types + 0 }, - { "delete_id", "u", types + 0 }, + { "error", "ous", wayland_types + 0 }, + { "delete_id", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_display_interface = { @@ -163,12 +163,12 @@ WL_EXPORT const struct wl_interface wl_display_interface = { }; static const struct wl_message wl_registry_requests[] = { - { "bind", "usun", types + 0 }, + { "bind", "usun", wayland_types + 0 }, }; static const struct wl_message wl_registry_events[] = { - { "global", "usu", types + 0 }, - { "global_remove", "u", types + 0 }, + { "global", "usu", wayland_types + 0 }, + { "global_remove", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_registry_interface = { @@ -178,7 +178,7 @@ WL_EXPORT const struct wl_interface wl_registry_interface = { }; static const struct wl_message wl_callback_events[] = { - { "done", "u", types + 0 }, + { "done", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_callback_interface = { @@ -188,8 +188,8 @@ WL_EXPORT const struct wl_interface wl_callback_interface = { }; static const struct wl_message wl_compositor_requests[] = { - { "create_surface", "n", types + 10 }, - { "create_region", "n", types + 11 }, + { "create_surface", "n", wayland_types + 10 }, + { "create_region", "n", wayland_types + 11 }, }; WL_EXPORT const struct wl_interface wl_compositor_interface = { @@ -199,9 +199,9 @@ WL_EXPORT const struct wl_interface wl_compositor_interface = { }; static const struct wl_message wl_shm_pool_requests[] = { - { "create_buffer", "niiiiu", types + 12 }, - { "destroy", "", types + 0 }, - { "resize", "i", types + 0 }, + { "create_buffer", "niiiiu", wayland_types + 12 }, + { "destroy", "", wayland_types + 0 }, + { "resize", "i", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_shm_pool_interface = { @@ -211,11 +211,11 @@ WL_EXPORT const struct wl_interface wl_shm_pool_interface = { }; static const struct wl_message wl_shm_requests[] = { - { "create_pool", "nhi", types + 18 }, + { "create_pool", "nhi", wayland_types + 18 }, }; static const struct wl_message wl_shm_events[] = { - { "format", "u", types + 0 }, + { "format", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_shm_interface = { @@ -225,11 +225,11 @@ WL_EXPORT const struct wl_interface wl_shm_interface = { }; static const struct wl_message wl_buffer_requests[] = { - { "destroy", "", types + 0 }, + { "destroy", "", wayland_types + 0 }, }; static const struct wl_message wl_buffer_events[] = { - { "release", "", types + 0 }, + { "release", "", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_buffer_interface = { @@ -239,17 +239,17 @@ WL_EXPORT const struct wl_interface wl_buffer_interface = { }; static const struct wl_message wl_data_offer_requests[] = { - { "accept", "u?s", types + 0 }, - { "receive", "sh", types + 0 }, - { "destroy", "", types + 0 }, - { "finish", "3", types + 0 }, - { "set_actions", "3uu", types + 0 }, + { "accept", "u?s", wayland_types + 0 }, + { "receive", "sh", wayland_types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "finish", "3", wayland_types + 0 }, + { "set_actions", "3uu", wayland_types + 0 }, }; static const struct wl_message wl_data_offer_events[] = { - { "offer", "s", types + 0 }, - { "source_actions", "3u", types + 0 }, - { "action", "3u", types + 0 }, + { "offer", "s", wayland_types + 0 }, + { "source_actions", "3u", wayland_types + 0 }, + { "action", "3u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_data_offer_interface = { @@ -259,18 +259,18 @@ WL_EXPORT const struct wl_interface wl_data_offer_interface = { }; static const struct wl_message wl_data_source_requests[] = { - { "offer", "s", types + 0 }, - { "destroy", "", types + 0 }, - { "set_actions", "3u", types + 0 }, + { "offer", "s", wayland_types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "set_actions", "3u", wayland_types + 0 }, }; static const struct wl_message wl_data_source_events[] = { - { "target", "?s", types + 0 }, - { "send", "sh", types + 0 }, - { "cancelled", "", types + 0 }, - { "dnd_drop_performed", "3", types + 0 }, - { "dnd_finished", "3", types + 0 }, - { "action", "3u", types + 0 }, + { "target", "?s", wayland_types + 0 }, + { "send", "sh", wayland_types + 0 }, + { "cancelled", "", wayland_types + 0 }, + { "dnd_drop_performed", "3", wayland_types + 0 }, + { "dnd_finished", "3", wayland_types + 0 }, + { "action", "3u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_data_source_interface = { @@ -280,18 +280,18 @@ WL_EXPORT const struct wl_interface wl_data_source_interface = { }; static const struct wl_message wl_data_device_requests[] = { - { "start_drag", "?oo?ou", types + 21 }, - { "set_selection", "?ou", types + 25 }, - { "release", "2", types + 0 }, + { "start_drag", "?oo?ou", wayland_types + 21 }, + { "set_selection", "?ou", wayland_types + 25 }, + { "release", "2", wayland_types + 0 }, }; static const struct wl_message wl_data_device_events[] = { - { "data_offer", "n", types + 27 }, - { "enter", "uoff?o", types + 28 }, - { "leave", "", types + 0 }, - { "motion", "uff", types + 0 }, - { "drop", "", types + 0 }, - { "selection", "?o", types + 33 }, + { "data_offer", "n", wayland_types + 27 }, + { "enter", "uoff?o", wayland_types + 28 }, + { "leave", "", wayland_types + 0 }, + { "motion", "uff", wayland_types + 0 }, + { "drop", "", wayland_types + 0 }, + { "selection", "?o", wayland_types + 33 }, }; WL_EXPORT const struct wl_interface wl_data_device_interface = { @@ -301,8 +301,8 @@ WL_EXPORT const struct wl_interface wl_data_device_interface = { }; static const struct wl_message wl_data_device_manager_requests[] = { - { "create_data_source", "n", types + 34 }, - { "get_data_device", "no", types + 35 }, + { "create_data_source", "n", wayland_types + 34 }, + { "get_data_device", "no", wayland_types + 35 }, }; WL_EXPORT const struct wl_interface wl_data_device_manager_interface = { @@ -312,7 +312,7 @@ WL_EXPORT const struct wl_interface wl_data_device_manager_interface = { }; static const struct wl_message wl_shell_requests[] = { - { "get_shell_surface", "no", types + 37 }, + { "get_shell_surface", "no", wayland_types + 37 }, }; WL_EXPORT const struct wl_interface wl_shell_interface = { @@ -322,22 +322,22 @@ WL_EXPORT const struct wl_interface wl_shell_interface = { }; static const struct wl_message wl_shell_surface_requests[] = { - { "pong", "u", types + 0 }, - { "move", "ou", types + 39 }, - { "resize", "ouu", types + 41 }, - { "set_toplevel", "", types + 0 }, - { "set_transient", "oiiu", types + 44 }, - { "set_fullscreen", "uu?o", types + 48 }, - { "set_popup", "ouoiiu", types + 51 }, - { "set_maximized", "?o", types + 57 }, - { "set_title", "s", types + 0 }, - { "set_class", "s", types + 0 }, + { "pong", "u", wayland_types + 0 }, + { "move", "ou", wayland_types + 39 }, + { "resize", "ouu", wayland_types + 41 }, + { "set_toplevel", "", wayland_types + 0 }, + { "set_transient", "oiiu", wayland_types + 44 }, + { "set_fullscreen", "uu?o", wayland_types + 48 }, + { "set_popup", "ouoiiu", wayland_types + 51 }, + { "set_maximized", "?o", wayland_types + 57 }, + { "set_title", "s", wayland_types + 0 }, + { "set_class", "s", wayland_types + 0 }, }; static const struct wl_message wl_shell_surface_events[] = { - { "ping", "u", types + 0 }, - { "configure", "uii", types + 0 }, - { "popup_done", "", types + 0 }, + { "ping", "u", wayland_types + 0 }, + { "configure", "uii", wayland_types + 0 }, + { "popup_done", "", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_shell_surface_interface = { @@ -347,21 +347,21 @@ WL_EXPORT const struct wl_interface wl_shell_surface_interface = { }; static const struct wl_message wl_surface_requests[] = { - { "destroy", "", types + 0 }, - { "attach", "?oii", types + 58 }, - { "damage", "iiii", types + 0 }, - { "frame", "n", types + 61 }, - { "set_opaque_region", "?o", types + 62 }, - { "set_input_region", "?o", types + 63 }, - { "commit", "", types + 0 }, - { "set_buffer_transform", "2i", types + 0 }, - { "set_buffer_scale", "3i", types + 0 }, - { "damage_buffer", "4iiii", types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "attach", "?oii", wayland_types + 58 }, + { "damage", "iiii", wayland_types + 0 }, + { "frame", "n", wayland_types + 61 }, + { "set_opaque_region", "?o", wayland_types + 62 }, + { "set_input_region", "?o", wayland_types + 63 }, + { "commit", "", wayland_types + 0 }, + { "set_buffer_transform", "2i", wayland_types + 0 }, + { "set_buffer_scale", "3i", wayland_types + 0 }, + { "damage_buffer", "4iiii", wayland_types + 0 }, }; static const struct wl_message wl_surface_events[] = { - { "enter", "o", types + 64 }, - { "leave", "o", types + 65 }, + { "enter", "o", wayland_types + 64 }, + { "leave", "o", wayland_types + 65 }, }; WL_EXPORT const struct wl_interface wl_surface_interface = { @@ -371,15 +371,15 @@ WL_EXPORT const struct wl_interface wl_surface_interface = { }; static const struct wl_message wl_seat_requests[] = { - { "get_pointer", "n", types + 66 }, - { "get_keyboard", "n", types + 67 }, - { "get_touch", "n", types + 68 }, - { "release", "5", types + 0 }, + { "get_pointer", "n", wayland_types + 66 }, + { "get_keyboard", "n", wayland_types + 67 }, + { "get_touch", "n", wayland_types + 68 }, + { "release", "5", wayland_types + 0 }, }; static const struct wl_message wl_seat_events[] = { - { "capabilities", "u", types + 0 }, - { "name", "2s", types + 0 }, + { "capabilities", "u", wayland_types + 0 }, + { "name", "2s", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_seat_interface = { @@ -389,20 +389,20 @@ WL_EXPORT const struct wl_interface wl_seat_interface = { }; static const struct wl_message wl_pointer_requests[] = { - { "set_cursor", "u?oii", types + 69 }, - { "release", "3", types + 0 }, + { "set_cursor", "u?oii", wayland_types + 69 }, + { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_pointer_events[] = { - { "enter", "uoff", types + 73 }, - { "leave", "uo", types + 77 }, - { "motion", "uff", types + 0 }, - { "button", "uuuu", types + 0 }, - { "axis", "uuf", types + 0 }, - { "frame", "5", types + 0 }, - { "axis_source", "5u", types + 0 }, - { "axis_stop", "5uu", types + 0 }, - { "axis_discrete", "5ui", types + 0 }, + { "enter", "uoff", wayland_types + 73 }, + { "leave", "uo", wayland_types + 77 }, + { "motion", "uff", wayland_types + 0 }, + { "button", "uuuu", wayland_types + 0 }, + { "axis", "uuf", wayland_types + 0 }, + { "frame", "5", wayland_types + 0 }, + { "axis_source", "5u", wayland_types + 0 }, + { "axis_stop", "5uu", wayland_types + 0 }, + { "axis_discrete", "5ui", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_pointer_interface = { @@ -412,16 +412,16 @@ WL_EXPORT const struct wl_interface wl_pointer_interface = { }; static const struct wl_message wl_keyboard_requests[] = { - { "release", "3", types + 0 }, + { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_keyboard_events[] = { - { "keymap", "uhu", types + 0 }, - { "enter", "uoa", types + 79 }, - { "leave", "uo", types + 82 }, - { "key", "uuuu", types + 0 }, - { "modifiers", "uuuuu", types + 0 }, - { "repeat_info", "4ii", types + 0 }, + { "keymap", "uhu", wayland_types + 0 }, + { "enter", "uoa", wayland_types + 79 }, + { "leave", "uo", wayland_types + 82 }, + { "key", "uuuu", wayland_types + 0 }, + { "modifiers", "uuuuu", wayland_types + 0 }, + { "repeat_info", "4ii", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_keyboard_interface = { @@ -431,17 +431,17 @@ WL_EXPORT const struct wl_interface wl_keyboard_interface = { }; static const struct wl_message wl_touch_requests[] = { - { "release", "3", types + 0 }, + { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_touch_events[] = { - { "down", "uuoiff", types + 84 }, - { "up", "uui", types + 0 }, - { "motion", "uiff", types + 0 }, - { "frame", "", types + 0 }, - { "cancel", "", types + 0 }, - { "shape", "6iff", types + 0 }, - { "orientation", "6if", types + 0 }, + { "down", "uuoiff", wayland_types + 84 }, + { "up", "uui", wayland_types + 0 }, + { "motion", "uiff", wayland_types + 0 }, + { "frame", "", wayland_types + 0 }, + { "cancel", "", wayland_types + 0 }, + { "shape", "6iff", wayland_types + 0 }, + { "orientation", "6if", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_touch_interface = { @@ -451,14 +451,14 @@ WL_EXPORT const struct wl_interface wl_touch_interface = { }; static const struct wl_message wl_output_requests[] = { - { "release", "3", types + 0 }, + { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_output_events[] = { - { "geometry", "iiiiissi", types + 0 }, - { "mode", "uiii", types + 0 }, - { "done", "2", types + 0 }, - { "scale", "2i", types + 0 }, + { "geometry", "iiiiissi", wayland_types + 0 }, + { "mode", "uiii", wayland_types + 0 }, + { "done", "2", wayland_types + 0 }, + { "scale", "2i", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_output_interface = { @@ -468,9 +468,9 @@ WL_EXPORT const struct wl_interface wl_output_interface = { }; static const struct wl_message wl_region_requests[] = { - { "destroy", "", types + 0 }, - { "add", "iiii", types + 0 }, - { "subtract", "iiii", types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "add", "iiii", wayland_types + 0 }, + { "subtract", "iiii", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_region_interface = { @@ -480,8 +480,8 @@ WL_EXPORT const struct wl_interface wl_region_interface = { }; static const struct wl_message wl_subcompositor_requests[] = { - { "destroy", "", types + 0 }, - { "get_subsurface", "noo", types + 90 }, + { "destroy", "", wayland_types + 0 }, + { "get_subsurface", "noo", wayland_types + 90 }, }; WL_EXPORT const struct wl_interface wl_subcompositor_interface = { @@ -491,12 +491,12 @@ WL_EXPORT const struct wl_interface wl_subcompositor_interface = { }; static const struct wl_message wl_subsurface_requests[] = { - { "destroy", "", types + 0 }, - { "set_position", "ii", types + 0 }, - { "place_above", "o", types + 93 }, - { "place_below", "o", types + 94 }, - { "set_sync", "", types + 0 }, - { "set_desync", "", types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "set_position", "ii", wayland_types + 0 }, + { "place_above", "o", wayland_types + 93 }, + { "place_below", "o", wayland_types + 94 }, + { "set_sync", "", wayland_types + 0 }, + { "set_desync", "", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_subsurface_interface = { diff --git a/tests/data/small-code-core.c b/tests/data/small-code-core.c index 28a00ab9..bd6d33de 100644 --- a/tests/data/small-code-core.c +++ b/tests/data/small-code-core.c @@ -32,7 +32,7 @@ extern const struct wl_interface another_intf_interface; extern const struct wl_interface intf_not_here_interface; -static const struct wl_interface *types[] = { +static const struct wl_interface *small_test_types[] = { NULL, &intf_not_here_interface, NULL, @@ -44,13 +44,13 @@ static const struct wl_interface *types[] = { }; static const struct wl_message intf_A_requests[] = { - { "rq1", "sun", types + 0 }, - { "rq2", "nsiufho", types + 1 }, - { "destroy", "", types + 0 }, + { "rq1", "sun", small_test_types + 0 }, + { "rq2", "nsiufho", small_test_types + 1 }, + { "destroy", "", small_test_types + 0 }, }; static const struct wl_message intf_A_events[] = { - { "hey", "", types + 0 }, + { "hey", "", small_test_types + 0 }, }; WL_EXPORT const struct wl_interface intf_A_interface = { diff --git a/tests/data/small-code.c b/tests/data/small-code.c index 28a00ab9..bd6d33de 100644 --- a/tests/data/small-code.c +++ b/tests/data/small-code.c @@ -32,7 +32,7 @@ extern const struct wl_interface another_intf_interface; extern const struct wl_interface intf_not_here_interface; -static const struct wl_interface *types[] = { +static const struct wl_interface *small_test_types[] = { NULL, &intf_not_here_interface, NULL, @@ -44,13 +44,13 @@ static const struct wl_interface *types[] = { }; static const struct wl_message intf_A_requests[] = { - { "rq1", "sun", types + 0 }, - { "rq2", "nsiufho", types + 1 }, - { "destroy", "", types + 0 }, + { "rq1", "sun", small_test_types + 0 }, + { "rq2", "nsiufho", small_test_types + 1 }, + { "destroy", "", small_test_types + 0 }, }; static const struct wl_message intf_A_events[] = { - { "hey", "", types + 0 }, + { "hey", "", small_test_types + 0 }, }; WL_EXPORT const struct wl_interface intf_A_interface = { diff --git a/tests/data/small-private-code.c b/tests/data/small-private-code.c index 5e0bc88f..fe035ffe 100644 --- a/tests/data/small-private-code.c +++ b/tests/data/small-private-code.c @@ -42,7 +42,7 @@ extern const struct wl_interface another_intf_interface; extern const struct wl_interface intf_not_here_interface; -static const struct wl_interface *types[] = { +static const struct wl_interface *small_test_types[] = { NULL, &intf_not_here_interface, NULL, @@ -54,13 +54,13 @@ static const struct wl_interface *types[] = { }; static const struct wl_message intf_A_requests[] = { - { "rq1", "sun", types + 0 }, - { "rq2", "nsiufho", types + 1 }, - { "destroy", "", types + 0 }, + { "rq1", "sun", small_test_types + 0 }, + { "rq2", "nsiufho", small_test_types + 1 }, + { "destroy", "", small_test_types + 0 }, }; static const struct wl_message intf_A_events[] = { - { "hey", "", types + 0 }, + { "hey", "", small_test_types + 0 }, }; WL_PRIVATE const struct wl_interface intf_A_interface = { From 766edf0243b1cd56c4a0d8a4ea03dd17ea49a119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Mon, 16 Sep 2019 01:02:30 +0100 Subject: [PATCH 0611/1152] Add $(RT_LIBS) to fixed-benchmark LD dependencies `tests/fixed-benchmark.c` calls `clock_gettime`. --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 868910cf..0d76865f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -286,6 +286,7 @@ cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp endif fixed_benchmark_SOURCES = tests/fixed-benchmark.c +fixed_benchmark_LDADD = $(RT_LIBS) os_wrappers_test_SOURCES = tests/os-wrappers-test.c os_wrappers_test_LDADD = libtest-runner.la From d5055ad913f4913c1bb1c17cef55049e30c191ad Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 22 Jul 2019 19:41:22 +0300 Subject: [PATCH 0612/1152] server: add wl_global_set_user_data When implementing a workaround for [1], one needs to accept a global to be bound even though it has become stale. Often, a global's user data is free'd when the global needs to be destroyed. Being able to set the global's user data (e.g. to NULL) can help preventing a use-after-free. (The alternative is to make the compositor responsible for keeping track of stale user data objects via e.g. refcounting.) [1]: https://gitlab.freedesktop.org/wayland/wayland/issues/10 Signed-off-by: Simon Ser --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 3e0272b5..68d7ddba 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -279,6 +279,9 @@ wl_global_get_interface(const struct wl_global *global); void * wl_global_get_user_data(const struct wl_global *global); +void +wl_global_set_user_data(struct wl_global *global, void *data); + struct wl_client * wl_client_create(struct wl_display *display, int fd); diff --git a/src/wayland-server.c b/src/wayland-server.c index 11cb7f57..8c537bb4 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1245,6 +1245,19 @@ wl_global_get_user_data(const struct wl_global *global) return global->data; } +/** Set the global's user data + * + * \param global The global object + * \param data The user data pointer + * + * \since 1.17.90 + */ +WL_EXPORT void +wl_global_set_user_data(struct wl_global *global, void *data) +{ + global->data = data; +} + /** Get the current serial number * * \param display The display object From 11623e8fddb924c7ae317f2eabac23785ae5e8d5 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Mon, 22 Jul 2019 15:58:49 +0200 Subject: [PATCH 0613/1152] =?UTF-8?q?wayland-shm:=20Don=E2=80=99t=20set=20?= =?UTF-8?q?SIGBUS=20handlers=20on=20unshrinkable=20fd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a client set the F_SEAL_SHRINK seal on the fd before passing it to the compositor, the kernel will ensure this fd won’t be able to shrink, ever. This allows us to avoid setting up the SIGBUS handlers on such file descriptors. Signed-off-by: Emmanuel Gil Peyrot --- src/wayland-shm.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 967b8759..b85e5a79 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -30,6 +30,8 @@ #define _GNU_SOURCE +#include "config.h" + #include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include "wayland-util.h" #include "wayland-private.h" @@ -60,6 +63,7 @@ struct wl_shm_pool { char *data; int32_t size; int32_t new_size; + bool sigbus_is_impossible; }; struct wl_shm_buffer { @@ -259,6 +263,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, uint32_t id, int fd, int32_t size) { struct wl_shm_pool *pool; + int seals; if (size <= 0) { wl_resource_post_error(resource, @@ -273,6 +278,15 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, goto err_close; } +#ifdef HAVE_MEMFD_CREATE + seals = fcntl(fd, F_GET_SEALS); + if (seals == -1) + seals = 0; + pool->sigbus_is_impossible = (seals & F_SEAL_SHRINK) ? true : false; +#else + pool->sigbus_is_impossible = false; +#endif + pool->internal_refcount = 1; pool->external_refcount = 0; pool->size = size; @@ -571,6 +585,9 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer) struct wl_shm_pool *pool = buffer->pool; struct wl_shm_sigbus_data *sigbus_data; + if (pool->sigbus_is_impossible) + return; + pthread_once(&wl_shm_sigbus_once, init_sigbus_data_key); sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); @@ -603,9 +620,13 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer) WL_EXPORT void wl_shm_buffer_end_access(struct wl_shm_buffer *buffer) { - struct wl_shm_sigbus_data *sigbus_data = - pthread_getspecific(wl_shm_sigbus_data_key); + struct wl_shm_pool *pool = buffer->pool; + struct wl_shm_sigbus_data *sigbus_data; + if (pool->sigbus_is_impossible) + return; + + sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); assert(sigbus_data && sigbus_data->access_count >= 1); if (--sigbus_data->access_count == 0) { From 39852f1146941fa93daf767b4ecfb41b2d11aaef Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 20 Jul 2019 23:36:29 +0300 Subject: [PATCH 0614/1152] server: add wl_global_remove This commit adds a new wl_global_remove function that just sends a global remove event without destroying it. See [1] for details. Removing a global is racy, because clients have no way to acknowledge they received the removal event. It's possible to mitigate the issue by sending the removal event, waiting a little and then destructing the global for real. The "wait a little" part is compositor policy. [1]: https://gitlab.freedesktop.org/wayland/wayland/issues/10 Signed-off-by: Simon Ser --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 42 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 68d7ddba..fd4fc3ee 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -246,6 +246,9 @@ wl_global_create(struct wl_display *display, int version, void *data, wl_global_bind_func_t bind); +void +wl_global_remove(struct wl_global *global); + void wl_global_destroy(struct wl_global *global); diff --git a/src/wayland-server.c b/src/wayland-server.c index 8c537bb4..c4c52ed9 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -25,6 +25,7 @@ #define _GNU_SOURCE +#include #include #include #include @@ -112,6 +113,7 @@ struct wl_global { void *data; wl_global_bind_func_t bind; struct wl_list link; + bool removed; }; struct wl_resource { @@ -992,7 +994,7 @@ display_get_registry(struct wl_client *client, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) - if (wl_global_is_visible(client, global)) + if (wl_global_is_visible(client, global) && !global->removed) wl_resource_post_event(registry_resource, WL_REGISTRY_GLOBAL, global->name, @@ -1208,6 +1210,7 @@ wl_global_create(struct wl_display *display, global->version = version; global->data = data; global->bind = bind; + global->removed = false; wl_list_insert(display->global_list.prev, &global->link); wl_list_for_each(resource, &display->registry_resource_list, link) @@ -1220,15 +1223,50 @@ wl_global_create(struct wl_display *display, return global; } +/** Remove the global + * + * \param global The Wayland global. + * + * Broadcast a global remove event to all clients without destroying the + * global. This function can only be called once per global. + * + * wl_global_destroy() removes the global and immediately destroys it. On + * the other end, this function only removes the global, allowing clients + * that have not yet received the global remove event to continue to bind to + * it. + * + * This can be used by compositors to mitigate clients being disconnected + * because a global has been added and removed too quickly. Compositors can call + * wl_global_remove(), then wait an implementation-defined amount of time, then + * call wl_global_destroy(). Note that the destruction of a global is still + * racy, since clients have no way to acknowledge that they received the remove + * event. + * + * \since 1.17.90 + */ WL_EXPORT void -wl_global_destroy(struct wl_global *global) +wl_global_remove(struct wl_global *global) { struct wl_display *display = global->display; struct wl_resource *resource; + if (global->removed) + wl_abort("wl_global_remove: called twice on the same " + "global '%s@%"PRIu32"'", global->interface->name, + global->name); + wl_list_for_each(resource, &display->registry_resource_list, link) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, global->name); + + global->removed = true; +} + +WL_EXPORT void +wl_global_destroy(struct wl_global *global) +{ + if (!global->removed) + wl_global_remove(global); wl_list_remove(&global->link); free(global); } From 4162863c41a030b2a2058fda54c902ecbe3433e5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 Sep 2019 17:12:03 +0300 Subject: [PATCH 0615/1152] tests: add a test for wl_global_remove This test makes sure that after wl_global_remove: * The global_remove event is sent to existing clients * Binding to the removed global still works * A new client will not see the removed global advertised Signed-off-by: Simon Ser --- tests/display-test.c | 134 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/tests/display-test.c b/tests/display-test.c index cf571fac..7b2647f7 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1487,3 +1487,137 @@ TEST(send_overflow_disconnection) display_destroy(d); } + +static void +registry_global_remove_before_handle_global(void *data, + struct wl_registry *registry, + uint32_t id, const char *intf, + uint32_t ver) +{ + uint32_t *id_ptr = data; + + if (strcmp(intf, wl_seat_interface.name) == 0) { + assert(*id_ptr == 0); + *id_ptr = id; + } +} + +static void +registry_global_remove_before_handle_global_remove(void *data, + struct wl_registry *registry, + uint32_t id) +{ + uint32_t *id_ptr = data; + + if (*id_ptr == id) { + *id_ptr = 0; + } +} + +/* This listener expects a uint32_t user data pointer, sets it to the wl_seat + * global ID when receiving a "global" event, and sets it to zero when receiving + * a "global_remove" event. */ +static const struct wl_registry_listener global_remove_before_registry_listener = { + registry_global_remove_before_handle_global, + registry_global_remove_before_handle_global_remove, +}; + +static void +global_remove_before_client(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + uint32_t global_id = 0, saved_global_id; + struct wl_seat *seat; + int ret; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, + &global_remove_before_registry_listener, + &global_id); + + ret = wl_display_roundtrip(c->wl_display); + assert(ret >= 0); + assert(global_id != 0); + saved_global_id = global_id; + + /* Wait for the compositor to remove the global */ + assert(stop_display(c, 1) >= 0); + + /* Check binding still works after the global has been removed. Also + * check we get the global_remove event. */ + seat = wl_registry_bind(registry, saved_global_id, &wl_seat_interface, 1); + ret = wl_display_roundtrip(c->wl_display); + assert(ret >= 0); + assert(global_id == 0); + + wl_seat_destroy(seat); + wl_registry_destroy(registry); + + client_disconnect(c); +} + +static void +registry_global_remove_after_handle_global(void *data, + struct wl_registry *registry, + uint32_t id, const char *intf, + uint32_t ver) +{ + /* Make sure the global isn't advertised anymore after being removed */ + assert(strcmp(intf, wl_seat_interface.name) != 0); +} + +static const struct wl_registry_listener global_remove_after_registry_listener = { + registry_global_remove_after_handle_global, + NULL, +}; + +static void +global_remove_after_client(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + uint32_t global_id = 0; + struct wl_seat *seat; + int ret; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, + &global_remove_after_registry_listener, + &global_id); + + ret = wl_display_roundtrip(c->wl_display); + assert(ret >= 0); + + wl_registry_destroy(registry); + + client_disconnect(c); +} + +TEST(global_remove) +{ + struct display *d; + struct wl_global *global; + int i; + + d = display_create(); + + global = wl_global_create(d->wl_display, &wl_seat_interface, + 1, d, bind_seat); + + /* Create a client before removing the global */ + client_create_noarg(d, global_remove_before_client); + + display_run(d); + + wl_global_remove(global); + + /* Create another client after removing the global */ + client_create_noarg(d, global_remove_after_client); + + display_resume(d); + + wl_global_destroy(global); + + display_destroy(d); +} From 8e0513410dd16a3f3b1d07745b613e5ae6141bd0 Mon Sep 17 00:00:00 2001 From: Jiayuan Ren Date: Thu, 24 Oct 2019 22:31:56 +0000 Subject: [PATCH 0616/1152] adding O_RDWR flag in the open() According to the manual of open: "The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR." --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index c4c52ed9..5f466a06 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1435,7 +1435,7 @@ wl_socket_lock(struct wl_socket *socket) snprintf(socket->lock_addr, sizeof socket->lock_addr, "%s%s", socket->addr.sun_path, LOCK_SUFFIX); - socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC, + socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC | O_RDWR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); if (socket->fd_lock < 0) { From 4a1f348c20157db7bd7c759fdeb23fbe8729c571 Mon Sep 17 00:00:00 2001 From: Joshua Watt Date: Fri, 25 Oct 2019 21:03:23 -0500 Subject: [PATCH 0617/1152] scanner: Add configure check for strndup Some platforms may not have strndup() (e.g. MinGW), so provide a equivalent implementation if it's not found. Signed-off-by: Joshua Watt --- configure.ac | 2 +- src/scanner.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c332107f..eb859771 100644 --- a/configure.ac +++ b/configure.ac @@ -63,7 +63,7 @@ fi AC_SUBST(GCC_CFLAGS) AC_CHECK_HEADERS([sys/prctl.h]) -AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl memfd_create]) +AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl memfd_create strndup]) # *BSD don't have libdl, but they have its functions in libc WESTON_SEARCH_LIBS([DL], [dl], [dlsym]) diff --git a/src/scanner.c b/src/scanner.c index 7ed1ba1a..2b3adbda 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -975,6 +975,17 @@ verify_arguments(struct parse_context *ctx, } +#ifndef HAVE_STRNDUP +char * +strndup(const char *s, size_t size) +{ + char *r = malloc(size + 1); + strncpy(r, s, size); + r[size] = '\0'; + return r; +} +#endif + static void end_element(void *data, const XML_Char *name) { From e7d88f35eb89cf0cc77cbddd834cacc63683a9cc Mon Sep 17 00:00:00 2001 From: Joshua Watt Date: Tue, 5 Nov 2019 09:09:50 -0600 Subject: [PATCH 0618/1152] Move wl_priv_signal to wayland-server-private.h Including wayland-server-core.h in wayland-private.h is problematic because wayland-private.h is included by wayland-scanner which should be able to build against non-POSIX platforms (e.g. MinGW). The only reason that wayland-server-core.h was included in wayland-private.h was for the wl_private_signal definitions, so move those to a wayland-server-private.h file that can be included by both wayland-server.c and the tests. Signed-off-by: Joshua Watt --- Makefile.am | 3 +- src/wayland-private.h | 22 +-------------- src/wayland-server-private.h | 53 ++++++++++++++++++++++++++++++++++++ src/wayland-server.c | 1 + tests/newsignal-test.c | 2 +- 5 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 src/wayland-server-private.h diff --git a/Makefile.am b/Makefile.am index 0d76865f..6c087cda 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,8 @@ libwayland_private_la_SOURCES = \ src/connection.c \ src/wayland-os.c \ src/wayland-os.h \ - src/wayland-private.h + src/wayland-private.h \ + src/wayland-server-private.h include_HEADERS = \ src/wayland-util.h \ diff --git a/src/wayland-private.h b/src/wayland-private.h index 8a97fabf..9bf8cb75 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -31,11 +31,11 @@ #include #include #include +#include #define WL_HIDE_DEPRECATED 1 #include "wayland-util.h" -#include "wayland-server-core.h" /* Invalid memory address */ #define WL_ARRAY_POISON_PTR (void *) 4 @@ -232,26 +232,6 @@ zalloc(size_t s) return calloc(1, s); } -struct wl_priv_signal { - struct wl_list listener_list; - struct wl_list emit_list; -}; - -void -wl_priv_signal_init(struct wl_priv_signal *signal); - -void -wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener); - -struct wl_listener * -wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify); - -void -wl_priv_signal_emit(struct wl_priv_signal *signal, void *data); - -void -wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data); - void wl_connection_close_fds_in(struct wl_connection *connection, int max); diff --git a/src/wayland-server-private.h b/src/wayland-server-private.h new file mode 100644 index 00000000..23fa4587 --- /dev/null +++ b/src/wayland-server-private.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2011 Intel Corporation + * Copyright © 2013 Jason Ekstrand + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef WAYLAND_SERVER_PRIVATE_H +#define WAYLAND_SERVER_PRIVATE_H + +#include "wayland-server-core.h" + +struct wl_priv_signal { + struct wl_list listener_list; + struct wl_list emit_list; +}; + +void +wl_priv_signal_init(struct wl_priv_signal *signal); + +void +wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener); + +struct wl_listener * +wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify); + +void +wl_priv_signal_emit(struct wl_priv_signal *signal, void *data); + +void +wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data); + +#endif diff --git a/src/wayland-server.c b/src/wayland-server.c index 5f466a06..3f48dfe4 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -46,6 +46,7 @@ #include "wayland-util.h" #include "wayland-private.h" +#include "wayland-server-private.h" #include "wayland-server.h" #include "wayland-os.h" diff --git a/tests/newsignal-test.c b/tests/newsignal-test.c index 47c429bb..f3a7bd98 100644 --- a/tests/newsignal-test.c +++ b/tests/newsignal-test.c @@ -26,7 +26,7 @@ #include #include "test-runner.h" -#include "wayland-private.h" +#include "wayland-server-private.h" static void signal_notify(struct wl_listener *listener, void *data) From 3a05d94dc25c0e6386fa5efd27885ceb0dc48396 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Thu, 2 Jan 2020 21:06:51 -0800 Subject: [PATCH 0619/1152] protocol: fix typo in wl_data_offer.set_actions description Signed-off-by: Michael Forney --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f1a13b75..1f645ba0 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -572,7 +572,7 @@ This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, - the drag source will receive wl_drag_source.cancelled. + the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action From b5bd24476d9b81ea6e23b479010ff9cd5495f2c2 Mon Sep 17 00:00:00 2001 From: asynts Date: Sat, 4 Jan 2020 14:40:09 +0100 Subject: [PATCH 0620/1152] doc: Expand the abbreviation "hw" to "hardware". Out of the context it is reasonably clear that "hw" is indeed an abbreviation for "hardware". The use of "hw" in this place doesn't seem to be a stylistic choice, but rather an oversight. Signed-off-by: Paul Scharnofske --- doc/publican/sources/Compositors.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/sources/Compositors.xml b/doc/publican/sources/Compositors.xml index eea627c7..ad27f61e 100644 --- a/doc/publican/sources/Compositors.xml +++ b/doc/publican/sources/Compositors.xml @@ -52,7 +52,7 @@ run nested under the system compositor. Nesting is feasible because the protocol is asynchronous; roundtrips would be too expensive when nesting is involved. If no system compositor is present, a - session compositor can run directly on the hw. + session compositor can run directly on the hardware. X applications can continue working under a session compositor From 8497144faae61844af2fc9ba4a29256aed0dd402 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Sun, 22 Jul 2018 10:00:26 +0100 Subject: [PATCH 0621/1152] build/doc: Ensure destination dir exists despite VPATH Make considers a variable called VPATH when trying to satisfy dependencies, e.g. for a target 'foo', it will consider the target extant if VPATH is '../../bar' and '../../bar/foo' exists. Part of the doc build, the '$(alldirs)' target, exists to create the target directories if they do not exist. For example, before generating xml/wayland-architecture.png, it will ensure the 'xml' target is considered up-to-date thanks to the target dependency. Creating $(srcdir)/doc/doxygen/xml thus means that the 'xml' dependency will be satisfied, so we'll never create the output directory, and the doc build will fail. Change the alldirs target list to be absolute paths, so VPATH will not be consulted and defeat the entire point of what we're trying to do. This fixes the Meson build, where we later create doc/doxygen/xml/meson.build. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen --- doc/doxygen/Makefile.am | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index f8b0b3aa..31d953c0 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -53,20 +53,21 @@ diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map)) dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") # Listing various directories that might need to be created. -alldirs := xml xml/Client xml/Server man/man3 html/Client html/Server +alldirsrel := xml xml/Client xml/Server man/man3 html/Client html/Server +alldirs := $(patsubst %,$(CURDIR)/%,$(alldirsrel)) $(diagrams): $(diagramssrc) $(diagram_maps): $(diagramssrc) -xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | xml/% +xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/xml/% $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_XML=YES"; \ echo "XML_OUTPUT=xml/$*"; \ echo "INPUT= $(scanned_src_files_$*)"; \ ) | $(DOXYGEN) - -html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | html/% +html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/html/% $(AM_V_GEN)(cat wayland.doxygen; \ echo "PROJECT_NAME=\"Wayland $* API\""; \ echo "GENERATE_HTML=YES"; \ @@ -74,7 +75,7 @@ html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_ echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \ ) | $(DOXYGEN) - -man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | man/man3 +man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | $(CURDIR)/man/man3 $(AM_V_GEN)(cat wayland.doxygen; \ echo "GENERATE_MAN=YES"; \ echo "MAN_OUTPUT=man"; \ @@ -82,10 +83,10 @@ man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayl echo "INPUT= $(scanned_src_files_man)"; \ ) | $(DOXYGEN) - -xml/%.png: $(diagramsdir)/%.gv | xml +xml/%.png: $(diagramsdir)/%.gv | $(CURDIR)/xml $(AM_V_GEN)$(DOT) -Tpng -o$@ $< -xml/%.map: $(diagramsdir)/%.gv | xml +xml/%.map: $(diagramsdir)/%.gv | $(CURDIR)/xml $(AM_V_GEN)$(DOT) -Tcmapx_np -o$@ $< # general rule to create one of the listed directories. From a77f6bf6c41f83520261cdf67c9819f8e36f8a3d Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 23 Apr 2018 14:29:15 +0100 Subject: [PATCH 0622/1152] Support running tests from different build directories The tests that run exec-fd-leak-checker expect the binary to be located in the current directory. This is not always the case; for instance, the binaries could be built under `tests`, but be invoked under the top-level build directory. We can use an environment variable to control what's the location of the test binaries, and fall back to the current directory if the variable is unset. Reviewed-by: Daniel Stone --- tests/test-helpers.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test-helpers.c b/tests/test-helpers.c index b2189d8e..20b66903 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -67,11 +68,19 @@ count_open_fds(void) void exec_fd_leak_check(int nr_expected_fds) { - const char *exe = "./exec-fd-leak-checker"; + const char *exe = "exec-fd-leak-checker"; char number[16] = { 0 }; + const char *test_build_dir = getenv("TEST_BUILD_DIR"); + char exe_path[256] = { 0 }; + + if (test_build_dir == NULL || test_build_dir[0] == 0) { + test_build_dir = "."; + } + + snprintf(exe_path, sizeof exe_path - 1, "%s/%s", test_build_dir, exe); snprintf(number, sizeof number - 1, "%d", nr_expected_fds); - execl(exe, exe, number, (char *)NULL); + execl(exe_path, exe, number, (char *)NULL); assert(0 && "execing fd leak checker failed"); } From 0d3044f2eaf66f2d87edad3c9545b9e1936f2019 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 11 Mar 2019 17:05:33 +0200 Subject: [PATCH 0623/1152] scanner: include config.h from command line Meson will need to build wayland-scanner twice with different config.h files, once for build and another for host machine. It will be easier to include the right config.h from compiler command line than playing with files. Signed-off-by: Pekka Paalanen --- Makefile.am | 1 + src/scanner.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6c087cda..411f2ac5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,6 +24,7 @@ pkgconfig_DATA = bin_PROGRAMS = wayland-scanner wayland_scanner_SOURCES = src/scanner.c +wayland_scanner_CPPFLAGS = $(AM_CPPFLAGS) -include config.h wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(LIBXML_CFLAGS) $(AM_CFLAGS) wayland_scanner_LDADD = $(EXPAT_LIBS) $(LIBXML_LIBS) libwayland-util.la pkgconfig_DATA += src/wayland-scanner.pc diff --git a/src/scanner.c b/src/scanner.c index 2b3adbda..b470c916 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -25,7 +25,6 @@ * SOFTWARE. */ -#include "config.h" #include "wayland-version.h" #include From 60acba6e0f13741a66f414cb9ac2e44e6048403b Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 23 Apr 2018 14:29:16 +0100 Subject: [PATCH 0624/1152] Add Meson build Meson is a next generation build system, simpler than Autotools and also faster and more portable. Most importantly, it will make integrating ASan easier in CI. The goal is to maintain feature parity of the Meson build with the Autotools build, until such time when we can drop the latter. Add a script which generates the desired Doxygen configuration for our various output formats and executes it using that configuration. This is not something Meson can or should do. Fixes: https://gitlab.freedesktop.org/wayland/wayland/issues/80 [daniels: Changed to bump version, use GitLab issues URL, remove header checks not used in any code, remove pre-pkg-config Expat support, added missing include paths to wayland-egl and cpp-compile-test, added GitLab CI. Bumped version, removed unnecessary pkg-config paths.] [daniels: Properly install into mandir/man3 via some gross paramaterisation, generate real stamp files.] Pekka: - squashed patches - removed MAKEFLAGS from meson CI - remove unused PACKAGE* defines - fix up scanner dependency handling - instead of host_scanner option, build wayland-scanner twice when cross-compiling - changed .pc files to match more closely the autotools versions - reorder doxygen man sources to reduce diff to autotools - fix pkgconfig.generate syntax warnings (new in Meson) - bump meson version to 0.47 for configure_file(copy) and run_command(check) - move doc tool checks into doc/meson.build, needed in more places - make all doc tools mandatory if building docs - check dot and doxygen versions - add build files under doc/publican - reindent to match Weston Meson style Simon: - Remove install arg from configure_file - Don't build wayland-scanner twice during cross-build - Fix naming of the threads dependency - Store tests in dict - Add missing HAVE_* decls for functions - Remove unused cc_native variable - Make doxygen targets a dict - Make dot_gv a dict - Use dicts in man_pages - Make decls use dicts - Make generated_headers use dicts - Align Meson version number with autotool's Signed-off-by: Pekka Paalanen Signed-off-by: Simon Ser --- .gitlab-ci.yml | 23 ++- cursor/meson.build | 27 ++++ doc/doxygen/.gitignore | 1 - doc/doxygen/gen-doxygen.py | 105 +++++++++++++ doc/doxygen/meson.build | 105 +++++++++++++ doc/doxygen/xml/Client/meson.build | 18 +++ doc/doxygen/xml/Server/meson.build | 18 +++ doc/doxygen/xml/meson.build | 22 +++ doc/man/meson.build | 46 ++++++ doc/meson.build | 38 +++++ doc/publican/meson.build | 30 ++++ doc/publican/sources/meson.build | 113 ++++++++++++++ egl/meson.build | 43 ++++++ meson.build | 104 +++++++++++++ meson_options.txt | 16 ++ src/meson.build | 228 +++++++++++++++++++++++++++++ tests/meson.build | 153 +++++++++++++++++++ 17 files changed, 1087 insertions(+), 3 deletions(-) create mode 100644 cursor/meson.build create mode 100755 doc/doxygen/gen-doxygen.py create mode 100644 doc/doxygen/meson.build create mode 100644 doc/doxygen/xml/Client/meson.build create mode 100644 doc/doxygen/xml/Server/meson.build create mode 100644 doc/doxygen/xml/meson.build create mode 100644 doc/man/meson.build create mode 100644 doc/meson.build create mode 100644 doc/publican/meson.build create mode 100644 doc/publican/sources/meson.build create mode 100644 egl/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 src/meson.build create mode 100644 tests/meson.build diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24896659..c665ef6b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,10 +9,11 @@ before_script: - echo '#!/bin/sh' > /usr/sbin/policy-rc.d - echo 'exit 101' >> /usr/sbin/policy-rc.d - chmod +x /usr/sbin/policy-rc.d + - echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/sources.list - apt-get update - - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl + - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson/stretch-backports -build-native: +build-native-autotools: stage: build script: - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" @@ -34,3 +35,21 @@ build-native: - build-*/wayland*/_build/sub/*.log - build-*/*.log - prefix-* + +build-native-meson: + stage: build + script: + - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" + - export PREFIX="$(pwd)/prefix-$BUILD_ID" + - export BUILDDIR="$(pwd)/build-$BUILD_ID" + - mkdir "$BUILDDIR" "$PREFIX" + - cd "$BUILDDIR" + - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons .. + - ninja -k0 test + - ninja clean + artifacts: + name: wayland-meson-$CI_COMMIT_SHA-$CI_JOB_ID + when: always + paths: + - build-meson/meson-logs + - prefix-* diff --git a/cursor/meson.build b/cursor/meson.build new file mode 100644 index 00000000..ae85ed9b --- /dev/null +++ b/cursor/meson.build @@ -0,0 +1,27 @@ +icondir = get_option('icon_directory') +if icondir == '' + icondir = join_paths(get_option('prefix'), get_option('datadir'), 'icons') +endif + +wayland_cursor = library( + 'wayland-cursor', + sources: [ + 'wayland-cursor.c', + 'os-compatibility.c', + 'xcursor.c', + ], + version: '0.0.0', + dependencies: [ wayland_client_dep ], + c_args: [ '-DICONDIR="@0@"'.format(icondir) ], + install: true, +) + +install_headers('wayland-cursor.h') + +pkgconfig.generate( + name: 'Wayland Cursor', + description: 'Wayland cursor helper library', + version: meson.project_version(), + libraries: wayland_cursor, + filebase: 'wayland-cursor', +) diff --git a/doc/doxygen/.gitignore b/doc/doxygen/.gitignore index a85e6c0d..d68d6fce 100644 --- a/doc/doxygen/.gitignore +++ b/doc/doxygen/.gitignore @@ -1,4 +1,3 @@ doxygen_sqlite3.db html/ wayland.doxygen -xml/ diff --git a/doc/doxygen/gen-doxygen.py b/doc/doxygen/gen-doxygen.py new file mode 100755 index 00000000..1bb07e57 --- /dev/null +++ b/doc/doxygen/gen-doxygen.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +import argparse +import datetime +import errno +import os +import subprocess +import sys + +# Custom configuration for each documentation format +doxygen_templates = { + 'xml': [ + 'GENERATE_XML=YES\n', + 'XML_OUTPUT={format}/{section}\n', + 'INPUT= {files}\n', + ], + 'html': [ + 'GENERATE_HTML=YES\n', + 'HTML_OUTPUT={format}/{section}\n', + 'PROJECT_NAME=\"Wayland {section} API\"\n', + 'INPUT= {files}\n', + ], + 'man': [ + 'GENERATE_MAN=YES\n', + 'MAN_OUTPUT={format}\n', + 'MAN_SUBDIR=.\n', + 'JAVADOC_AUTOBRIEF=NO\n', + 'INPUT= {files}\n', + ], +} + +def load_doxygen_file(doxyfile): + with open(doxyfile, 'r') as f: + res = f.readlines() + return res + +def get_template(outformat): + for (k,v) in doxygen_templates.items(): + if outformat.startswith(k): + return v + +def gen_doxygen_file(data, outformat, section, files): + for l in get_template(outformat): + data.append(l.format(format=outformat, section=section, files=' '.join(files))) + return data + +parser = argparse.ArgumentParser(description='Generate docs with Doxygen') +parser.add_argument('doxygen_file', + help='The doxygen file to use') +parser.add_argument('files', + help='The list of files to parse', + metavar='FILES', + nargs='+') +parser.add_argument('--builddir', + help='The build directory', + metavar='DIR', + default='.') +parser.add_argument('--section', + help='The section to build', + metavar='NAME', + default='Client') +parser.add_argument('--output-format', + help='The output format: xml, html, man', + metavar='FORMAT', + default='xml') +parser.add_argument('--stamp', + help='Stamp file to output', + metavar='STAMP_FILE', + nargs='?', + type=argparse.FileType('w')) + +args = parser.parse_args() + +# Merge the doxyfile with our custom templates +conf = load_doxygen_file(args.doxygen_file) +conf = gen_doxygen_file(conf, args.output_format, args.section, args.files) + +# Doxygen is not clever enough to create the directories it +# needs beforehand +try: + os.makedirs(os.path.join(args.builddir, args.output_format)) +except OSError as e: + if e.errno != errno.EEXIST: + raise e + +# Run Doxygen with the generated doxyfile +cmd = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE) +cmd.stdin.write(''.join(conf).encode('utf-8')) +cmd.stdin.close() +if cmd.wait() != 0: + sys.exit(1) + +# This is a bit of a hack; Doxygen will generate way more files than we +# want to install, but there's no way to know how many at configuration +# time. Since we want to install only the wl_* man pages anyway, we can +# delete the other files and let Meson install the whole man3 subdirectory +if args.output_format.startswith('man'): + manpath = os.path.join(args.builddir, args.output_format) + for filename in os.listdir(manpath): + full_path = os.path.join(manpath, filename) + if not filename.startswith('wl_'): + os.remove(full_path) + +if args.stamp: + args.stamp.write(str(datetime.datetime.now())) diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build new file mode 100644 index 00000000..c39b2826 --- /dev/null +++ b/doc/doxygen/meson.build @@ -0,0 +1,105 @@ +# Here be dragons + +dot_gv = { + 'wayland-architecture': files('dot/wayland-architecture.gv'), + 'x-architecture': files('dot/x-architecture.gv'), +} + +# This is a workaround for Meson's custom_target() directive, which +# currently does not support outputs pointing to a sub-directory +# XXX: try turning these into maps, so they can be indexed with picture name +dot_png = [] +dot_map = [] + +doxygen_conf = configuration_data() +doxygen_conf.set('VERSION', meson.project_version()) +doxygen_conf.set('top_builddir', meson.build_root()) +wayland_doxygen = configure_file( + input: 'wayland.doxygen.in', + output: 'wayland.doxygen', + configuration: doxygen_conf, +) + +shared_files = files([ + '../../src/wayland-util.h', +]) + +client_files = files([ + '../../src/wayland-client.c', + '../../src/wayland-client.h', + '../../src/wayland-client-core.h', +]) + +server_files = files([ + '../../src/event-loop.c', + '../../src/wayland-server.c', + '../../src/wayland-server.h', + '../../src/wayland-server-core.h', + '../../src/wayland-shm.c', +]) + +extra_client_files = [ + 'mainpage.dox', + wayland_client_protocol_h, +] + +extra_server_files = [ + 'mainpage.dox', + wayland_server_protocol_h, +] + +gen_doxygen = find_program('gen-doxygen.py') + +subdir('xml') + +formats = { + 'html': { + 'Client': shared_files + client_files + extra_client_files, + 'Server': shared_files + server_files + extra_server_files, + }, +} + +foreach f_name, sections: formats + foreach s_name, s_files: sections + t_name = '@0@-@1@-doc'.format(f_name, s_name) + + # We do not really need an output file, but Meson + # will complain if one is not set, so we use a + # dummy 'stamp' file + custom_target( + t_name, + command: [ + gen_doxygen, + # XXX pass doxygen path as argument + '--builddir=@OUTDIR@', + '--section=@0@'.format(s_name), + '--output-format=@0@'.format(f_name), + '--stamp=doc/doxygen/@0@.stamp'.format(t_name), + wayland_doxygen, + '@INPUT@', + ], + input: s_files, + output: '@0@.stamp'.format(t_name), + depends: [dot_png, dot_map], + build_by_default: true, + ) + endforeach +endforeach + +man_files = shared_files + server_files + client_files +custom_target( + 'man-pages-3', + command: [ + gen_doxygen, + '--builddir=@OUTDIR@', + '--output-format=man3', + '--stamp=doc/doxygen/man3.stamp', + wayland_doxygen, + '@INPUT@', + ], + input: man_files, + output: 'man3', + build_by_default: true, + install: true, + install_dir: join_paths(get_option('prefix'), get_option('mandir')), +) diff --git a/doc/doxygen/xml/Client/meson.build b/doc/doxygen/xml/Client/meson.build new file mode 100644 index 00000000..849c30da --- /dev/null +++ b/doc/doxygen/xml/Client/meson.build @@ -0,0 +1,18 @@ +tgt = custom_target( + 'xml-Client-doc', + command: [ + gen_doxygen, + # XXX pass doxygen path as argument + '--builddir=@OUTDIR@', + '--section=Client', + '--output-format=xml', + wayland_doxygen, + '@INPUT@', + ], + input: [ shared_files, client_files ], + output: [ 'combine.xslt', 'index.xml' ], + depends: [dot_png, dot_map] +) + +doxygen_Client_combine_xslt = tgt[0] +doxygen_Client_index_xml = tgt[1] diff --git a/doc/doxygen/xml/Server/meson.build b/doc/doxygen/xml/Server/meson.build new file mode 100644 index 00000000..4792c1bc --- /dev/null +++ b/doc/doxygen/xml/Server/meson.build @@ -0,0 +1,18 @@ +tgt = custom_target( + 'xml-Server-doc', + command: [ + gen_doxygen, + # XXX pass doxygen path as argument + '--builddir=@OUTDIR@', + '--section=Server', + '--output-format=xml', + wayland_doxygen, + '@INPUT@', + ], + input: [ shared_files, server_files ], + output: [ 'combine.xslt', 'index.xml' ], + depends: [dot_png, dot_map] +) + +doxygen_Server_combine_xslt = tgt[0] +doxygen_Server_index_xml = tgt[1] diff --git a/doc/doxygen/xml/meson.build b/doc/doxygen/xml/meson.build new file mode 100644 index 00000000..6d55c53a --- /dev/null +++ b/doc/doxygen/xml/meson.build @@ -0,0 +1,22 @@ +# dot_png: list of PNG targets +# dot_map: list of MAP targets +foreach name, infile: dot_gv + dot_png += custom_target( + name + '.png', + command: [ dot, '-Tpng', '-o@OUTPUT@', '@INPUT@' ], + input: infile, + output: name + '.png', + install: true, + install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images') + ) + + dot_map += custom_target( + name + '.map', + command: [ dot, '-Tcmapx_np', '-o@OUTPUT@', '@INPUT@' ], + input: infile, + output: name + '.map', + ) +endforeach + +subdir('Client') +subdir('Server') diff --git a/doc/man/meson.build b/doc/man/meson.build new file mode 100644 index 00000000..0fd4cec7 --- /dev/null +++ b/doc/man/meson.build @@ -0,0 +1,46 @@ +man_pages = [ + { + 'section': '3', + 'xml': 'wl_display_connect.xml', + 'name': 'wl_display_connect', + 'alias': 'wl_display_connect_to_fd', + } +] + +xsltproc_opts = [ + '--nonet', + '--stringparam', 'man.authors.section.enabled', '0', + '--stringparam', 'man.copyright.section.enabled', '0', + '--stringparam', 'funcsynopsis.style', 'ansi', + '--stringparam', 'man.output.quietly', '1', +] + +foreach page: man_pages + section_number = page['section'] + xml_input = page['xml'] + name = page['name'] + alias = page.get('alias', '') + + man_output = name + '.' + section_number + if alias != '' + alias_output = alias + '.' + section_number + else + alias_output = [] + endif + + man_page = custom_target( + name + '-man', + command: [ + xsltproc, + xsltproc_opts, + '-o', '@OUTPUT0@', + manpage_xsl, + '@INPUT@', + ], + input: xml_input, + output: [ man_output, alias_output ], + install: true, + install_dir: join_paths(get_option('prefix'), get_option('mandir'), 'man' + section_number), + build_by_default: true, + ) +endforeach diff --git a/doc/meson.build b/doc/meson.build new file mode 100644 index 00000000..0b46f48c --- /dev/null +++ b/doc/meson.build @@ -0,0 +1,38 @@ +dot = find_program('dot') +doxygen = find_program('doxygen') +xsltproc = find_program('xsltproc') +xmlto = find_program('xmlto') + +cmd = run_command(doxygen, '--version', check: true) +message('doxygen: ' + cmd.stdout().strip()) +vers = cmd.stdout().strip() +if vers.version_compare('< 1.6.0') + error('Doxygen 1.6 or later is required for building documentation, found @0@.'.format(vers)) +endif + +cmd = run_command(dot, '-V', check: true) +message('dot: ' + cmd.stderr().strip()) +vers = cmd.stderr().split('version')[1].strip().split(' ')[0] +if vers.version_compare('< 2.26.0') + error('Dot (Graphviz) 2.26 or later is required for building documentation, found @0@.'.format(vers)) +endif + +manpage_xsl = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl' +cmd = run_command(xsltproc, '--nonet', manpage_xsl) +if cmd.returncode() != 0 + error('The style sheet for man pages providing "@0@" was not found.'.format(manpage_xsl)) +endif + +publican_install_prefix = join_paths( + get_option('prefix'), + get_option('datadir'), + 'doc', + meson.project_name(), + 'Wayland', 'en-US' +) + +publican_html_dir = 'html' + +subdir('doxygen') +subdir('man') +subdir('publican') diff --git a/doc/publican/meson.build b/doc/publican/meson.build new file mode 100644 index 00000000..898ca4fc --- /dev/null +++ b/doc/publican/meson.build @@ -0,0 +1,30 @@ +merge_mapcoords_xsl = files('merge-mapcoords.xsl') + +subdir('sources') + +custom_target( + 'Wayland-docbook-html', + command: [ + xmlto, + '--skip-validation', + '--stringparam', 'chunk.section.depth=0', + '--stringparam', 'toc.section.depth=1', + '--stringparam', 'html.stylesheet=css/default.css', + '-o', '@OUTPUT@', + 'html', + '@INPUT@' + ], + input: publican_processed_main, + output: publican_html_dir, + depend_files: publican_copied_sources, + depends: [ + publican_processed_targets, + ClientAPI_xml, + ServerAPI_xml, + ProtocolSpec_xml, + ProtocolInterfaces_xml + ], + build_by_default: true, + install: true, + install_dir: publican_install_prefix +) diff --git a/doc/publican/sources/meson.build b/doc/publican/sources/meson.build new file mode 100644 index 00000000..52f3a681 --- /dev/null +++ b/doc/publican/sources/meson.build @@ -0,0 +1,113 @@ +ProtocolSpec_xml = custom_target( + 'ProtocolSpec.xml', + command: [ xsltproc, '-o', '@OUTPUT@', files('../protocol-to-docbook.xsl'), '@INPUT@' ], + input: wayland_protocol_xml, + output: 'ProtocolSpec.xml' +) + +ProtocolInterfaces_xml = custom_target( + 'ProtocolInterfaces.xml', + command: [ xsltproc, '-o', '@OUTPUT@', files('../protocol-interfaces-to-docbook.xsl'), '@INPUT@' ], + input: wayland_protocol_xml, + output: 'ProtocolInterfaces.xml' +) + +ClientAPI_combined = custom_target( + 'ClientAPI-combined', + command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], + input: [ doxygen_Client_combine_xslt, doxygen_Client_index_xml ], + output: 'ClientAPI-combined.xml' +) + +to_publican_xsl = files('../doxygen-to-publican.xsl') + +ClientAPI_xml = custom_target( + 'ClientAPI.xml', + command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Client', to_publican_xsl, '@INPUT@' ], + input: ClientAPI_combined, + output: 'ClientAPI.xml' +) + +ServerAPI_combined = custom_target( + 'ServerAPI-combined', + command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], + input: [ doxygen_Server_combine_xslt, doxygen_Server_index_xml ], + output: 'ServerAPI-combined.xml' +) + +ServerAPI_xml = custom_target( + 'ServerAPI.xml', + command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Server', to_publican_xsl, '@INPUT@' ], + input: ServerAPI_combined, + output: 'ServerAPI.xml' +) + + +publican_sources = [ + 'Wayland.ent', + # 'Wayland.xml', # handled specially + 'Book_Info.xml', + 'Author_Group.xml', + 'Foreword.xml', + 'Preface.xml', + 'Revision_History.xml', + 'Protocol.xml', + 'Xwayland.xml', + 'Compositors.xml', + 'Client.xml', + 'Server.xml' +] + +publican_processed_main = configure_file( + input: 'Wayland.xml', + output: 'Wayland.xml', + copy: true +) + +publican_copied_sources = [] +foreach src: publican_sources + publican_copied_sources += configure_file( + input: src, + output: src, + copy: true + ) +endforeach + +publican_processed_sources = [ + 'Architecture.xml', + 'Introduction.xml' +] + +publican_processed_targets = [] +foreach src: publican_processed_sources + publican_processed_targets += custom_target( + src, + command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'basedir', '.', merge_mapcoords_xsl, '@INPUT@' ], + input: src, + output: src + ) +endforeach + +publican_css_sources = files([ + 'css/brand.css', + 'css/common.css', + 'css/default.css', + 'css/epub.css', + 'css/print.css' +]) + +install_data( + publican_css_sources, + install_dir: join_paths(publican_install_prefix, publican_html_dir, 'css') +) + +publican_img_sources = files([ + 'images/icon.svg', + 'images/wayland.png', + 'images/xwayland-architecture.png' +]) + +install_data( + publican_img_sources, + install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images') +) diff --git a/egl/meson.build b/egl/meson.build new file mode 100644 index 00000000..dee9b1dd --- /dev/null +++ b/egl/meson.build @@ -0,0 +1,43 @@ +wayland_egl = library( + 'wayland-egl', + sources: [ + 'wayland-egl.c', + wayland_client_protocol_h + ], + include_directories: src_inc, + version: '1.0.0', + install: true +) + +executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') + +nm_path = find_program('nm').path() + +test( + 'wayland-egl symbols check', + find_program('wayland-egl-symbols-check'), + env: [ + 'WAYLAND_EGL_LIB=@0@'.format(wayland_egl.full_path()), + 'NM=@0@'.format(nm_path) + ] +) + +install_headers([ + 'wayland-egl.h', + 'wayland-egl-core.h', + 'wayland-egl-backend.h' +]) + +pkgconfig.generate( + name: 'wayland-egl', + description: 'Frontend wayland-egl library', + version: '18.1.0', + requires: 'wayland-client', + libraries: wayland_egl +) + +pkgconfig.generate( + name: 'wayland-egl-backend', + description: 'Backend wayland-egl interface', + version: '3' +) diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..be2129cf --- /dev/null +++ b/meson.build @@ -0,0 +1,104 @@ +project( + 'wayland', 'c', 'cpp', + version: '1.17.90', + license: 'MIT', + meson_version: '>= 0.47.0', + default_options: [ + 'warning_level=2', + 'buildtype=debugoptimized' + ] +) + +config_h = configuration_data() +config_h.set_quoted('PACKAGE', meson.project_name()) +config_h.set_quoted('PACKAGE_VERSION', meson.project_version()) + +compiler_flags = [ + '-Wno-unused-parameter', + '-Wstrict-prototypes', + '-Wmissing-prototypes', + '-fvisibility=hidden', +] + +cc = meson.get_compiler('c') +add_project_arguments( + cc.get_supported_arguments(compiler_flags), + language: 'c' +) + +foreach h: [ 'sys/prctl.h' ] + config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) +endforeach + +have_funcs = [ + 'accept4', + 'mkostemp', + 'posix_fallocate', + 'prctl', + 'memfd_create', + 'strndup', +] +foreach f: have_funcs + config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f)) +endforeach + +if get_option('libraries') + ffi_dep = dependency('libffi') + + decls = [ + { 'header': 'sys/signalfd.h', 'symbol': 'SFD_CLOEXEC' }, + { 'header': 'sys/timerfd.h', 'symbol': 'TFD_CLOEXEC' }, + { 'header': 'time.h', 'symbol': 'CLOCK_MONOTONIC' }, + ] + + foreach d: decls + if not cc.has_header_symbol(d['header'], d['symbol']) + error('@0@ is needed to compile Wayland libraries'.format(d['symbol'])) + endif + endforeach +endif + +scanner_deps = [ dependency('expat') ] + +if get_option('dtd_validation') + scanner_deps += dependency('libxml-2.0') + config_h.set('HAVE_LIBXML', 1) +endif + +configure_file( + output: 'config.h', + configuration: config_h, +) + +add_project_arguments([ '-DHAVE_CONFIG_H' ], language: 'c') + +pkgconfig = import('pkgconfig') + +wayland_protocol_xml = files('protocol/wayland.xml') + +root_inc = include_directories('.') +protocol_inc = include_directories('protocol') +src_inc = include_directories('src') + +subdir('src') + +if get_option('libraries') + subdir('cursor') + subdir('egl') + subdir('tests') +endif + +if get_option('documentation') + subdir('doc') +endif + +install_data([ + 'wayland-scanner.mk', + 'protocol/wayland.xml', + 'protocol/wayland.dtd', +]) + +install_data( + [ 'wayland-scanner.m4' ], + install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'aclocal'), +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..76314f79 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,16 @@ +option('libraries', + description: 'Compile Wayland libraries', + type: 'boolean', + value: 'true') +option('documentation', + description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)', + type: 'boolean', + value: 'true') +option('dtd_validation', + description: 'Validate the protocol DTD (requires libxml2)', + type: 'boolean', + value: 'true') +option('icon_directory', + description: 'Location used to look for cursors (defaults to ${datadir}/icons if unset)', + type: 'string', + value: '') diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 00000000..26e52693 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,228 @@ +wayland_version = meson.project_version().split('.') +wayland_version_h = configuration_data() +wayland_version_h.set('WAYLAND_VERSION', meson.project_version()) +wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int()) +wayland_version_h.set('WAYLAND_VERSION_MINOR', wayland_version[1].to_int()) +wayland_version_h.set('WAYLAND_VERSION_MICRO', wayland_version[2].to_int()) +configure_file( + input: 'wayland-version.h.in', + output: 'wayland-version.h', + configuration: wayland_version_h, + install_dir: join_paths(get_option('prefix'), get_option('includedir')) +) + +wayland_util = static_library( + 'wayland-util', + sources: 'wayland-util.c' +) + +wayland_util_dep = declare_dependency( + link_with: wayland_util, + include_directories: include_directories('.') +) + +# wayland-scanner + +configure_file( + input: '../protocol/wayland.dtd', + output: 'wayland.dtd.embed', + copy: true +) + +wayland_scanner_sources = [ 'scanner.c', 'dtddata.S' ] +wayland_scanner_includes = [ root_inc, protocol_inc ] + +wayland_scanner = executable( + 'wayland-scanner', + wayland_scanner_sources, + c_args: [ '-include', 'config.h' ], + include_directories: wayland_scanner_includes, + dependencies: [ scanner_deps, wayland_util_dep, ], + install: true +) + +pkgconfig.generate( + name: 'Wayland Scanner', + description: 'Wayland scanner', + version: meson.project_version(), + variables: [ + 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), + 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()), + 'bindir=' + join_paths('${prefix}', get_option('bindir')), + 'wayland_scanner=${bindir}/wayland-scanner' + ], + filebase: 'wayland-scanner' +) + +if meson.is_cross_build() + scanner_dep = dependency('wayland-scanner', native: true) + wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) +else + wayland_scanner_for_build = wayland_scanner +endif + +if get_option('libraries') + mathlib_dep = cc.find_library('m', required: false) + threads_dep = dependency('threads', required: false) + + wayland_private = static_library( + 'wayland-private', + sources: [ + 'connection.c', + 'wayland-os.c' + ], + dependencies: [ ffi_dep, ] + ) + + wayland_private_dep = declare_dependency( + link_with: wayland_private, + include_directories: include_directories('.') + ) + + generated_headers = [ + { + 'scanner_args': ['server-header'], + 'output': 'wayland-server-protocol.h', + 'install': true, + }, + { + 'scanner_args': ['server-header', '-c'], + 'output': 'wayland-server-protocol-core.h', + 'install': false, + }, + { + 'scanner_args': ['client-header'], + 'output': 'wayland-client-protocol.h', + 'install': true, + }, + { + 'scanner_args': ['client-header', '-c'], + 'output': 'wayland-client-protocol-core.h', + 'install': false, + }, + ] + + foreach gen: generated_headers + scanner_args = gen['scanner_args'] + output_file = gen['output'] + install_file = gen['install'] + install_dir = join_paths(get_option('prefix'), get_option('includedir')) + target_name = output_file.underscorify() + + target = custom_target( + target_name, + command: [ + wayland_scanner_for_build, scanner_args, + '@INPUT@', '@OUTPUT@' + ], + input: wayland_protocol_xml, + output: output_file, + install: install_file, + install_dir: install_dir + ) + + set_variable(target_name, target) + endforeach + + wayland_protocol_c = custom_target( + 'protocol source', + command: [ + wayland_scanner_for_build, 'public-code', '@INPUT@', '@OUTPUT@' + ], + input: wayland_protocol_xml, + output: 'wayland-protocol.c' + ) + + wayland_server = library( + 'wayland-server', + sources: [ + wayland_server_protocol_core_h, + wayland_server_protocol_h, + wayland_protocol_c, + 'wayland-server.c', + 'wayland-shm.c', + 'event-loop.c' + ], + version: '0.1.0', + dependencies: [ + ffi_dep, + wayland_private_dep, + wayland_util_dep, + mathlib_dep, + threads_dep + ], + include_directories: root_inc, + install: true + ) + + wayland_server_dep = declare_dependency( + link_with: wayland_server, + include_directories: [ root_inc, include_directories('.') ], + dependencies: [ ffi_dep, mathlib_dep, threads_dep ], + sources: [ + wayland_server_protocol_core_h, + wayland_server_protocol_h + ] + ) + + pkgconfig.generate( + wayland_server, + name: 'Wayland Server', + description: 'Server side implementation of the Wayland protocol', + version: meson.project_version(), + filebase: 'wayland-server', + variables: [ + 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), + 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()) + ] + ) + + wayland_client = library( + 'wayland-client', + sources: [ + wayland_client_protocol_core_h, + wayland_client_protocol_h, + wayland_protocol_c, + 'wayland-client.c' + ], + version: '0.3.0', + dependencies: [ + ffi_dep, + wayland_private_dep, + wayland_util_dep, + mathlib_dep, + threads_dep + ], + include_directories: root_inc, + install: true + ) + + pkgconfig.generate( + wayland_client, + name: 'Wayland Client', + description: 'Wayland client side library', + version: meson.project_version(), + filebase: 'wayland-client', + variables: [ + 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), + 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()) + ] + ) + + wayland_client_dep = declare_dependency( + link_with: wayland_client, + include_directories: [ root_inc, include_directories('.') ], + sources: [ + wayland_client_protocol_core_h, + wayland_client_protocol_h + ] + ) + + install_headers([ + 'wayland-util.h', + 'wayland-server.h', + 'wayland-server-core.h', + 'wayland-client.h', + 'wayland-client-core.h', + ]) +endif diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 00000000..6daec2ed --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,153 @@ +test_runner = static_library( + 'test-runner', + sources: [ + 'test-runner.c', + 'test-helpers.c', + 'test-compositor.c' + ], + include_directories: [ root_inc, src_inc ], + dependencies: [ + cc.find_library('dl', required: false), + dependency('threads'), + ffi_dep, + wayland_util_dep, + wayland_private_dep, + wayland_client_dep, + wayland_server_dep + ] +) + +test_runner_dep = declare_dependency( + link_with: test_runner, + include_directories: [ src_inc ], + dependencies: [ + dependency('threads'), + cc.find_library('dl', required: false) + ] +) + +tests_protocol_xml = files('../protocol/tests.xml') + +tests_server_protocol_h = custom_target( + 'test server protocol header', + command: [ wayland_scanner_for_build, 'server-header', '@INPUT@', '@OUTPUT@' ], + input: tests_protocol_xml, + output: 'tests-server-protocol.h' +) + +tests_client_protocol_c = custom_target( + 'test client protocol header', + command: [ wayland_scanner_for_build, 'client-header', '@INPUT@', '@OUTPUT@' ], + input: tests_protocol_xml, + output: 'tests-client-protocol.h' +) + +tests_protocol_c = custom_target( + 'test protocol source', + command: [ wayland_scanner_for_build, 'public-code', '@INPUT@', '@OUTPUT@' ], + input: tests_protocol_xml, + output: 'tests-protocol.c' +) + +benchmark( + 'fixed-benchmark', + executable( + 'fixed-benchmark', + 'fixed-benchmark.c', + dependencies: test_runner_dep + ) +) + +executable( + 'exec-fd-leak-checker', + 'exec-fd-leak-checker.c', + dependencies: test_runner_dep +) + +test( + 'cpp-compile-test', + executable( + 'cpp-compile-test', + 'cpp-compile-test.cpp', + wayland_server_protocol_core_h, + include_directories: src_inc + ) +) + +sed_path = find_program('sed').path() + +test( + 'scanner-test', + find_program('scanner-test.sh'), + env: [ + 'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()), + 'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()), + 'SED=@0@'.format(sed_path), + 'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()), + ], +) + +tests = { + 'array-test': [], + 'client-test': [ wayland_server_protocol_h ], + 'display-test': [ + tests_server_protocol_h, + tests_client_protocol_c, + tests_protocol_c, + ], + 'connection-test': [ wayland_server_protocol_h ], + 'event-loop-test': [ wayland_server_protocol_h ], + 'fixed-test': [], + 'interface-test': [ wayland_client_protocol_h ], + 'list-test': [], + 'map-test': [], + 'sanity-test' : [ wayland_server_protocol_h ], + 'socket-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + 'queue-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + 'signal-test': [ wayland_server_protocol_h ], + 'newsignal-test': [ + # wayland-server.c is needed here to access wl_priv_* functions + files('../src/wayland-server.c'), + wayland_server_protocol_h, + ], + 'resources-test': [ wayland_server_protocol_core_h ], + 'message-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + 'compositor-introspection-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + 'protocol-logger-test': [ + wayland_server_protocol_core_h, + wayland_client_protocol_core_h, + ], + 'headers-test': [ + 'headers-protocol-test.c', + 'headers-protocol-core-test.c', + wayland_server_protocol_core_h, + wayland_client_protocol_core_h, + ], + 'os-wrappers-test': [], +} + +foreach test_name, test_extra_sources: tests + test_sources = [ test_name + '.c' ] + test_extra_sources + test_deps = [test_runner_dep] + bin = executable(test_name, test_sources, dependencies: test_deps) + test( + test_name, + bin, + env: [ + 'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()), + 'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()), + ], + ) +endforeach From 89a38bfaa40147d65e0240f24e1619a24cc38dd7 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 13 Jan 2020 13:51:43 +0000 Subject: [PATCH 0625/1152] display-test: Remove unused variables At higher warning levels, GCC complains about unused variables. Remove two completely unused, and one set-but-not-used, variables from display-test to make it happy. Signed-off-by: Daniel Stone --- tests/display-test.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index 7b2647f7..533916c4 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1455,7 +1455,6 @@ send_overflow_client(void *data) TEST(send_overflow_disconnection) { struct display *d; - struct client_info *c; char tmp; int rpipe[2]; int i; @@ -1464,7 +1463,7 @@ TEST(send_overflow_disconnection) d = display_create(); - c = client_create(d, send_overflow_client, &rpipe); + (void) client_create(d, send_overflow_client, &rpipe); /* Close write end of the pipe, so that the later read() call gets * interrupted if the client dies */ @@ -1578,7 +1577,6 @@ global_remove_after_client(void *data) struct client *c = client_connect(); struct wl_registry *registry; uint32_t global_id = 0; - struct wl_seat *seat; int ret; registry = wl_display_get_registry(c->wl_display); @@ -1598,7 +1596,6 @@ TEST(global_remove) { struct display *d; struct wl_global *global; - int i; d = display_create(); From c2ce50b9d7bd470c2fe8faa4b0d996fca0fcbbaa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Jan 2020 19:27:19 +0100 Subject: [PATCH 0626/1152] build: check wayland-scanner version We need the --strict flag, released in wayland 1.14.0. Signed-off-by: Simon Ser --- src/meson.build | 2 +- wayland-scanner.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meson.build b/src/meson.build index 26e52693..7421a8d2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -55,7 +55,7 @@ pkgconfig.generate( ) if meson.is_cross_build() - scanner_dep = dependency('wayland-scanner', native: true) + scanner_dep = dependency('wayland-scanner', native: true, version: '>=1.14.0') wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) else wayland_scanner_for_build = wayland_scanner diff --git a/wayland-scanner.m4 b/wayland-scanner.m4 index 4e4222ad..2b222e8b 100644 --- a/wayland-scanner.m4 +++ b/wayland-scanner.m4 @@ -1,7 +1,7 @@ AC_DEFUN([WAYLAND_SCANNER_RULES], [ PKG_PROG_PKG_CONFIG - PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner]) + PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner >= 1.14.0]) wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` AC_SUBST([wayland_scanner]) From 555d3b8a9b5214a30774019a341f96759c75de02 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Jan 2020 19:32:44 +0100 Subject: [PATCH 0627/1152] Revert "build: check wayland-scanner version" This reverts commit c2ce50b9d7bd470c2fe8faa4b0d996fca0fcbbaa. Pushed by mistake. Sorry about that. --- src/meson.build | 2 +- wayland-scanner.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meson.build b/src/meson.build index 7421a8d2..26e52693 100644 --- a/src/meson.build +++ b/src/meson.build @@ -55,7 +55,7 @@ pkgconfig.generate( ) if meson.is_cross_build() - scanner_dep = dependency('wayland-scanner', native: true, version: '>=1.14.0') + scanner_dep = dependency('wayland-scanner', native: true) wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) else wayland_scanner_for_build = wayland_scanner diff --git a/wayland-scanner.m4 b/wayland-scanner.m4 index 2b222e8b..4e4222ad 100644 --- a/wayland-scanner.m4 +++ b/wayland-scanner.m4 @@ -1,7 +1,7 @@ AC_DEFUN([WAYLAND_SCANNER_RULES], [ PKG_PROG_PKG_CONFIG - PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner >= 1.14.0]) + PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner]) wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` AC_SUBST([wayland_scanner]) From e449232f37256a7db3311399b311984271efa1e7 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Tue, 24 Dec 2019 23:57:29 -0500 Subject: [PATCH 0628/1152] tests: Fix race condition in send overflow test This change ensures that the compositor process is not able to respond to any of the noop requests sent by the client process, by using the test compositor's `stop_display` mechanism to coordinate when the compositor should stop processing messages. (Before this change, it was possible that one of the calls of wl_event_loop_dispatch in the compositor process could respond to all the client's noop requests before returning.) Signed-off-by: Manuel Stoeckl --- tests/display-test.c | 25 +++++++++++++++---------- tests/test-compositor.c | 7 ++++++- tests/test-compositor.h | 13 +++++++++++-- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index 533916c4..f155d08e 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1431,6 +1431,9 @@ send_overflow_client(void *data) int *pipes = data; char tmp = '\0'; + /* Request to break out of 'display_run' in the main process */ + assert(stop_display(c, 1) >= 0); + /* On Linux, the Unix socket default buffer size is <=256KB, and * each noop request requires 8 bytes; the buffer should thus * overflow within about 32K /unhandled/ iterations */ @@ -1457,7 +1460,7 @@ TEST(send_overflow_disconnection) struct display *d; char tmp; int rpipe[2]; - int i; + ssize_t ret; assert(pipe(rpipe) != -1); @@ -1469,16 +1472,18 @@ TEST(send_overflow_disconnection) * interrupted if the client dies */ close(rpipe[1]); - /* At least 2 loops of this are needed to respond for the client to - * set up the test interface */ - for (i = 0; i < 5; i++) { - wl_display_flush_clients(d->wl_display); - wl_event_loop_dispatch(wl_display_get_event_loop(d->wl_display), -1); - } + /* Run the display until the client sends a `stop_display`, then + * send a resume message but don't actually look at new messages */ + display_run(d); + display_post_resume_events(d); + wl_display_flush_clients(d->wl_display); - /* Wait until all noop requests have been sent, or until client - * process aborts */ - (void)read(rpipe[0], &tmp, sizeof(tmp)); + /* Wait until all noop requests have been sent (read returns 1), or + * until client process aborts (read returns 0) */ + do { + ret = read(rpipe[0], &tmp, sizeof(tmp)); + } while (ret == -1 && errno == EINTR); + assert(ret != -1); close(rpipe[0]); /* For a clean shutdown */ diff --git a/tests/test-compositor.c b/tests/test-compositor.c index bd2b0156..468ee56d 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -366,7 +366,7 @@ display_run(struct display *d) } void -display_resume(struct display *d) +display_post_resume_events(struct display *d) { struct wfr *wfr, *next; @@ -380,7 +380,12 @@ display_resume(struct display *d) assert(wl_list_empty(&d->waiting_for_resume)); d->wfr_num = 0; +} +void +display_resume(struct display *d) +{ + display_post_resume_events(d); wl_display_run(d->wl_display); } diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 90999b2f..180dad25 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -90,12 +90,21 @@ struct display *display_create(void); void display_destroy(struct display *d); void display_run(struct display *d); +/* This function posts the display_resumed event to all waiting clients, + * so that after flushing events the clients will stop waiting and continue. + * + * (Calling `display_run` after this function will resume the display loop.) + */ +void display_post_resume_events(struct display *d); /* After n clients called stop_display(..., n), the display * is stopped and can process the code after display_run(). - * This function rerun the display again and send display_resumed - * event to waiting clients, so the clients will stop waiting and continue */ + * + * This function posts the display_resumed event to the waiting + * clients, so that the clients will stop waiting and continue; + * it then reruns the display. */ void display_resume(struct display *d); + struct client_info *client_create_with_name(struct display *d, void (*client_main)(void *data), void *data, From 6ddd0636e0d4124c64993329b11a6c656a1841df Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 11 Jan 2020 12:38:46 -0500 Subject: [PATCH 0629/1152] tests: Ensure that overflow test always overflows While the default Unix socket buffer size on Linux is relatively small, on some computers the default size may be configured to be huge, making the overflow test never actually overflow the Wayland display socket. The changed code now explicitly sets the display socket send buffer size to be small enough to guarantee an overflow. Signed-off-by: Manuel Stoeckl --- tests/display-test.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index f155d08e..3db7c95a 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1430,13 +1430,19 @@ send_overflow_client(void *data) int i, err = 0; int *pipes = data; char tmp = '\0'; + int sock, optval = 16384; + + /* Limit the send buffer size for the display socket to guarantee + * that the test will cause an overflow. */ + sock = wl_display_get_fd(c->wl_display); + assert(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == 0); /* Request to break out of 'display_run' in the main process */ assert(stop_display(c, 1) >= 0); - /* On Linux, the Unix socket default buffer size is <=256KB, and - * each noop request requires 8 bytes; the buffer should thus - * overflow within about 32K /unhandled/ iterations */ + /* On Linux, the actual socket data + metadata space is twice `optval`; + * since each noop request requires 8 bytes, the buffer should overflow + * within <=4096 iterations. */ for (i = 0; i < 1000000; i++) { noop_request(c); err = wl_display_get_error(c->wl_display); From 1f8fe8b966b59cd8af22c6a4a3b81996ff057c22 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Jan 2020 18:56:35 +0100 Subject: [PATCH 0630/1152] meson: use strict wayland-scanner mode Otherwise an invalid protocol will print warnings to stdout but won't make the build fail. Signed-off-by: Simon Ser --- src/meson.build | 4 ++-- tests/meson.build | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/meson.build b/src/meson.build index 26e52693..7945965f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -112,7 +112,7 @@ if get_option('libraries') target = custom_target( target_name, command: [ - wayland_scanner_for_build, scanner_args, + wayland_scanner_for_build, '-s', scanner_args, '@INPUT@', '@OUTPUT@' ], input: wayland_protocol_xml, @@ -127,7 +127,7 @@ if get_option('libraries') wayland_protocol_c = custom_target( 'protocol source', command: [ - wayland_scanner_for_build, 'public-code', '@INPUT@', '@OUTPUT@' + wayland_scanner_for_build, '-s', 'public-code', '@INPUT@', '@OUTPUT@' ], input: wayland_protocol_xml, output: 'wayland-protocol.c' diff --git a/tests/meson.build b/tests/meson.build index 6daec2ed..c28a2a39 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -30,21 +30,21 @@ tests_protocol_xml = files('../protocol/tests.xml') tests_server_protocol_h = custom_target( 'test server protocol header', - command: [ wayland_scanner_for_build, 'server-header', '@INPUT@', '@OUTPUT@' ], + command: [ wayland_scanner_for_build, '-s', 'server-header', '@INPUT@', '@OUTPUT@' ], input: tests_protocol_xml, output: 'tests-server-protocol.h' ) tests_client_protocol_c = custom_target( 'test client protocol header', - command: [ wayland_scanner_for_build, 'client-header', '@INPUT@', '@OUTPUT@' ], + command: [ wayland_scanner_for_build, '-s', 'client-header', '@INPUT@', '@OUTPUT@' ], input: tests_protocol_xml, output: 'tests-client-protocol.h' ) tests_protocol_c = custom_target( 'test protocol source', - command: [ wayland_scanner_for_build, 'public-code', '@INPUT@', '@OUTPUT@' ], + command: [ wayland_scanner_for_build, '-s', 'public-code', '@INPUT@', '@OUTPUT@' ], input: tests_protocol_xml, output: 'tests-protocol.c' ) From bfd4362fc2932c08df686945bc4ca276dcff08e4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Jan 2020 19:18:13 +0100 Subject: [PATCH 0631/1152] autotools: use strict wayland-scanner mode Otherwise an invalid protocol will print warnings to stdout but won't make the build fail. Signed-off-by: Simon Ser --- Makefile.am | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 411f2ac5..928874c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,22 +98,22 @@ pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml if USE_HOST_SCANNER - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code $< $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s code $< $@ else - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) public-code $< $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s public-code $< $@ endif protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header $< $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header $< $@ protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header $< $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header $< $@ protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header -c < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header -c < $< > $@ protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header -c < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header -c < $< > $@ BUILT_SOURCES = \ $(nodist_libwayland_server_la_SOURCES) \ From fab3cb3bfedd649d668e37d81b90c3dbad9f4fad Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Jan 2020 19:27:19 +0100 Subject: [PATCH 0632/1152] build: check wayland-scanner version We need the --strict flag, released in wayland 1.14.0. Signed-off-by: Simon Ser --- src/meson.build | 2 +- wayland-scanner.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meson.build b/src/meson.build index 7945965f..3e8c9bfb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -55,7 +55,7 @@ pkgconfig.generate( ) if meson.is_cross_build() - scanner_dep = dependency('wayland-scanner', native: true) + scanner_dep = dependency('wayland-scanner', native: true, version: '>=1.14.0') wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) else wayland_scanner_for_build = wayland_scanner diff --git a/wayland-scanner.m4 b/wayland-scanner.m4 index 4e4222ad..2b222e8b 100644 --- a/wayland-scanner.m4 +++ b/wayland-scanner.m4 @@ -1,7 +1,7 @@ AC_DEFUN([WAYLAND_SCANNER_RULES], [ PKG_PROG_PKG_CONFIG - PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner]) + PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner >= 1.14.0]) wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` AC_SUBST([wayland_scanner]) From a0d941e411820e6d49a528757f53fd0f6ce53f3e Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Fri, 3 Jan 2020 14:25:04 -0500 Subject: [PATCH 0633/1152] event-loop-test: Verify proper timer cancellation The implementation of timer event sources based on timerfds ensured specific edge-case behavior with regards to removing and updating timers: Calls to `wl_event_loop_dispatch` will dispatch all timer event sources that have expired up to that point, with one exception. When multiple timer event sources are due to be dispatched in a single call of `wl_event_loop_dispatch`, calling wl_event_source_remove` from within a timer event source callback will prevent the removed event source's callback from being called. Note that disarming or updating one of the later timers that is due to be dispatched, from within a timer callback, will NOT prevent that timer's callback from being invoked by `wl_event_loop_dispatch`. This commit adds a test that verifies the above behavior. (Because epoll_wait is not documented to return timerfds in chronological order, (although it does, in practice), the test code does not depend on the order in which timers are dispatched.) Signed-off-by: Manuel Stoeckl --- tests/event-loop-test.c | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index 9659815b..3002e6d2 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "wayland-private.h" @@ -330,6 +331,80 @@ TEST(event_loop_timer_updates) wl_event_loop_destroy(loop); } +struct timer_cancel_context { + struct wl_event_source *timers[4]; + struct timer_cancel_context *back_refs[4]; + int order[4]; + int called, first; +}; + +static int +timer_cancel_callback(void *data) { + struct timer_cancel_context **context_ref = data; + struct timer_cancel_context *context = *context_ref; + int i = (int)(context_ref - context->back_refs); + + context->called++; + context->order[i] = context->called; + + if (context->called == 1) { + context->first = i; + /* Removing a timer always prevents its callback from + * being called ... */ + wl_event_source_remove(context->timers[(i + 1) % 4]); + /* ... but disarming or rescheduling a timer does not, + * (in the case where the modified timers had already expired + * as of when `wl_event_loop_dispatch` was called.) */ + assert(wl_event_source_timer_update(context->timers[(i + 2) % 4], + 0) == 0); + assert(wl_event_source_timer_update(context->timers[(i + 3) % 4], + 2000000000) == 0); + } + + return 0; +} + +TEST(event_loop_timer_cancellation) +{ + struct wl_event_loop *loop = wl_event_loop_create(); + struct timer_cancel_context context; + int i; + + memset(&context, 0, sizeof(context)); + + /* Test that when multiple timers are dispatched in a single call + * of `wl_event_loop_dispatch`, that having some timers run code + * to modify the other timers only actually prevents the other timers + * from running their callbacks when the those timers are removed, not + * when they are disarmed or rescheduled. */ + + for (i = 0; i < 4; i++) { + context.back_refs[i] = &context; + context.timers[i] = + wl_event_loop_add_timer(loop, timer_cancel_callback, + &context.back_refs[i]); + assert(context.timers[i]); + + assert(wl_event_source_timer_update(context.timers[i], 1) == 0); + } + + usleep(MSEC_TO_USEC(2)); + assert(wl_event_loop_dispatch(loop, 0) == 0); + + /* Tracking which timer was first makes this test independent of the + * actual timer dispatch order, which is not guaranteed by the docs */ + assert(context.order[context.first] == 1); + assert(context.order[(context.first + 1) % 4] == 0); + assert(context.order[(context.first + 2) % 4] > 1); + assert(context.order[(context.first + 3) % 4] > 1); + + wl_event_source_remove(context.timers[context.first]); + wl_event_source_remove(context.timers[(context.first + 2) % 4]); + wl_event_source_remove(context.timers[(context.first + 3) % 4]); + + wl_event_loop_destroy(loop); +} + struct event_loop_destroy_listener { struct wl_listener listener; int done; From 75d14834570bb0c851e792b520814888fb324c08 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Thu, 16 Jan 2020 08:07:41 -0500 Subject: [PATCH 0634/1152] event-loop-test: Confirm distant timers do not fire This change expands the `event_loop_timer` test to use two different timers with different timeouts; it now implicitly checks that e.g. both timers do not expire at the same time, and that the first timer expiring does not prevent the second from doing so. (While such failure modes are unlikely with timer event sources based on individual timerfds, they are possible when multiple timers share a common timerfd.) Signed-off-by: Manuel Stoeckl --- tests/event-loop-test.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index 3002e6d2..e9e636cb 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -230,18 +230,33 @@ timer_callback(void *data) TEST(event_loop_timer) { struct wl_event_loop *loop = wl_event_loop_create(); - struct wl_event_source *source; + struct wl_event_source *source1, *source2; int got_it = 0; - source = wl_event_loop_add_timer(loop, timer_callback, &got_it); - assert(source); - wl_event_source_timer_update(source, 10); - wl_event_loop_dispatch(loop, 0); - assert(!got_it); - wl_event_loop_dispatch(loop, 20); - assert(got_it == 1); + source1 = wl_event_loop_add_timer(loop, timer_callback, &got_it); + assert(source1); + wl_event_source_timer_update(source1, 20); - wl_event_source_remove(source); + source2 = wl_event_loop_add_timer(loop, timer_callback, &got_it); + assert(source2); + wl_event_source_timer_update(source2, 100); + + /* Check that the timer marked for 20 msec from now fires within 30 + * msec, and that the timer marked for 100 msec is expected to fire + * within an additional 90 msec. (Some extra wait time is provided to + * account for reasonable code execution / thread preemption delays.) */ + + wl_event_loop_dispatch(loop, 0); + assert(got_it == 0); + wl_event_loop_dispatch(loop, 30); + assert(got_it == 1); + wl_event_loop_dispatch(loop, 0); + assert(got_it == 1); + wl_event_loop_dispatch(loop, 90); + assert(got_it == 2); + + wl_event_source_remove(source1); + wl_event_source_remove(source2); wl_event_loop_destroy(loop); } From 60a8d29ad8526c18cc670612e2c94f443873011a Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 21 Dec 2019 10:15:56 -0500 Subject: [PATCH 0635/1152] event-loop: Track timer event sources in userspace libwayland now uses only one file descriptor to keep track of all the timer event sources associated with an event loop. An array-based binary heap is used to determine which event source has the earliest deadline. (Previously, each timer event source had its own timerfd, making it easy for the a process using many timer event sources to run out of file descriptors.) Signed-off-by: Manuel Stoeckl --- src/event-loop.c | 454 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 420 insertions(+), 34 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index 017ab27c..339ff197 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -23,6 +23,7 @@ * SOFTWARE. */ +#include #include #include #include @@ -45,19 +46,11 @@ /** \cond INTERNAL */ -struct wl_event_loop { - int epoll_fd; - struct wl_list check_list; - struct wl_list idle_list; - struct wl_list destroy_list; +#define TIMER_REMOVED -2 - struct wl_signal destroy_signal; -}; - -struct wl_event_source_interface { - int (*dispatch)(struct wl_event_source *source, - struct epoll_event *ep); -}; +struct wl_event_loop; +struct wl_event_source_interface; +struct wl_event_source_timer; struct wl_event_source { struct wl_event_source_interface *interface; @@ -67,6 +60,30 @@ struct wl_event_source { int fd; }; +struct wl_timer_heap { + struct wl_event_source base; + /* pointers to the user-visible event sources */ + struct wl_event_source_timer **data; + int space, active, count; +}; + +struct wl_event_loop { + int epoll_fd; + struct wl_list check_list; + struct wl_list idle_list; + struct wl_list destroy_list; + + struct wl_signal destroy_signal; + + struct wl_timer_heap timers; +}; + +struct wl_event_source_interface { + int (*dispatch)(struct wl_event_source *source, + struct epoll_event *ep); +}; + + struct wl_event_source_fd { struct wl_event_source base; wl_event_loop_fd_func_t func; @@ -215,31 +232,319 @@ wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask) struct wl_event_source_timer { struct wl_event_source base; wl_event_loop_timer_func_t func; + struct wl_event_source_timer *next_due; + struct timespec deadline; + int heap_idx; }; -/** \endcond */ +static int +noop_dispatch(struct wl_event_source *source, + struct epoll_event *ep) { + return 0; +} + +struct wl_event_source_interface timer_heap_source_interface = { + noop_dispatch, +}; + +static bool +time_lt(struct timespec ta, struct timespec tb) +{ + if (ta.tv_sec != tb.tv_sec) { + return ta.tv_sec < tb.tv_sec; + } + return ta.tv_nsec < tb.tv_nsec; +} + +static int +set_timer(int timerfd, struct timespec deadline) { + struct itimerspec its; + + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value = deadline; + return timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &its, NULL); +} + +static int +clear_timer(int timerfd) +{ + struct itimerspec its; + + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 0; + return timerfd_settime(timerfd, 0, &its, NULL); +} + +static void +wl_timer_heap_init(struct wl_timer_heap *timers, struct wl_event_loop *loop) +{ + timers->base.fd = -1; + timers->base.data = NULL; + wl_list_init(&timers->base.link); + timers->base.interface = &timer_heap_source_interface; + timers->base.loop = loop; + + loop->timers.data = NULL; + loop->timers.active = 0; + loop->timers.space = 0; + loop->timers.count = 0; +} + +static void +wl_timer_heap_release(struct wl_timer_heap *timers) +{ + if (timers->base.fd != -1) { + close(timers->base.fd); + } + free(timers->data); +} + +static int +wl_timer_heap_ensure_timerfd(struct wl_timer_heap *timers) +{ + struct epoll_event ep; + int timer_fd; + + if (timers->base.fd != -1) + return 0; + + memset(&ep, 0, sizeof ep); + ep.events = EPOLLIN; + ep.data.ptr = timers; + + timer_fd = timerfd_create(CLOCK_MONOTONIC, + TFD_CLOEXEC | TFD_NONBLOCK); + if (timer_fd < 0) + return -1; + + if (epoll_ctl(timers->base.loop->epoll_fd, + EPOLL_CTL_ADD, timer_fd, &ep) < 0) { + close(timer_fd); + return -1; + } + + timers->base.fd = timer_fd; + return 0; +} + +static int +wl_timer_heap_reserve(struct wl_timer_heap *timers) +{ + struct wl_event_source_timer **n; + int new_space; + + if (timers->count + 1 > timers->space) { + new_space = timers->space >= 8 ? timers->space * 2 : 8; + n = realloc(timers->data, (size_t)new_space * sizeof(*n)); + if (!n) { + wl_log("Allocation failure when expanding timer list"); + return -1; + } + timers->data = n; + timers->space = new_space; + } + + timers->count++; + return 0; +} + +static void +wl_timer_heap_unreserve(struct wl_timer_heap *timers) +{ + struct wl_event_source_timer **n; + + timers->count--; + + if (timers->space >= 16 && timers->space >= 4 * timers->count) { + n = realloc(timers->data, (size_t)timers->space / 2 * sizeof(*n)); + if (!n) { + wl_log("Reallocation failure when shrinking timer list"); + return; + } + timers->data = n; + timers->space = timers->space / 2; + } +} + +static int +heap_set(struct wl_event_source_timer **data, + struct wl_event_source_timer *a, + int idx) +{ + int tmp; + + tmp = a->heap_idx; + a->heap_idx = idx; + data[a->heap_idx] = a; + + return tmp; +} + +static void +heap_sift_down(struct wl_event_source_timer **data, + int num_active, + struct wl_event_source_timer *source) +{ + struct wl_event_source_timer *child, *other_child; + int cursor_idx; + struct timespec key; + + cursor_idx = source->heap_idx; + key = source->deadline; + while (1) { + int lchild_idx = cursor_idx * 2 + 1; + + if (lchild_idx >= num_active) { + break; + } + + child = data[lchild_idx]; + if (lchild_idx + 1 < num_active) { + other_child = data[lchild_idx + 1]; + if (time_lt(other_child->deadline, child->deadline)) + child = other_child; + } + + if (time_lt(child->deadline, key)) + cursor_idx = heap_set(data, child, cursor_idx); + else + break; + } + + heap_set(data, source, cursor_idx); +} + +static void +heap_sift_up(struct wl_event_source_timer **data, + struct wl_event_source_timer *source) +{ + int cursor_idx; + struct timespec key; + + cursor_idx = source->heap_idx; + key = source->deadline; + while (cursor_idx > 0) { + struct wl_event_source_timer *parent = + data[(cursor_idx - 1) / 2]; + + if (time_lt(key, parent->deadline)) + cursor_idx = heap_set(data, parent, cursor_idx); + else + break; + } + heap_set(data, source, cursor_idx); +} + +/* requires timer be armed */ +static void +wl_timer_heap_disarm(struct wl_timer_heap *timers, + struct wl_event_source_timer *source) +{ + struct wl_event_source_timer *last_end_evt; + int old_source_idx; + + assert(source->heap_idx >= 0); + + old_source_idx = source->heap_idx; + source->heap_idx = -1; + source->deadline.tv_sec = 0; + source->deadline.tv_nsec = 0; + + last_end_evt = timers->data[timers->active - 1]; + timers->data[timers->active - 1] = NULL; + timers->active--; + + if (old_source_idx == timers->active) + return; + + timers->data[old_source_idx] = last_end_evt; + last_end_evt->heap_idx = old_source_idx; + + /* Move the displaced (active) element to its proper place. + * Only one of sift-down and sift-up will have any effect */ + heap_sift_down(timers->data, timers->active, last_end_evt); + heap_sift_up(timers->data, last_end_evt); +} + +/* requires timer be disarmed */ +static void +wl_timer_heap_arm(struct wl_timer_heap *timers, + struct wl_event_source_timer *source, + struct timespec deadline) +{ + assert(source->heap_idx == -1); + + source->deadline = deadline; + timers->data[timers->active] = source; + source->heap_idx = timers->active; + timers->active++; + heap_sift_up(timers->data, source); +} + + +static int +wl_timer_heap_dispatch(struct wl_timer_heap *timers) +{ + struct timespec now; + struct wl_event_source_timer *root; + struct wl_event_source_timer *list_cursor = NULL, *list_tail = NULL; + + clock_gettime(CLOCK_MONOTONIC, &now); + + while (timers->active > 0) { + root = timers->data[0]; + if (time_lt(now, root->deadline)) + break; + + wl_timer_heap_disarm(timers, root); + + if (list_cursor == NULL) + list_cursor = root; + else + list_tail->next_due = root; + list_tail = root; + } + if (list_tail) + list_tail->next_due = NULL; + + if (timers->active > 0) { + if (set_timer(timers->base.fd, timers->data[0]->deadline) < 0) + return -1; + } else { + if (clear_timer(timers->base.fd) < 0) + return -1; + } + + /* Execute precisely the functions for events before `now`, in order. + * Because wl_event_loop_dispatch ignores return codes, do the same + * here as well */ + for (; list_cursor; list_cursor = list_cursor->next_due) { + if (list_cursor->base.fd != TIMER_REMOVED) + list_cursor->func(list_cursor->base.data); + } + + return 0; +} static int wl_event_source_timer_dispatch(struct wl_event_source *source, struct epoll_event *ep) { - struct wl_event_source_timer *timer_source = - (struct wl_event_source_timer *) source; - uint64_t expires; - int len; + struct wl_event_source_timer *timer; - len = read(source->fd, &expires, sizeof expires); - if (!(len == -1 && errno == EAGAIN) && len != sizeof expires) - /* Is there anything we can do here? Will this ever happen? */ - wl_log("timerfd read error: %s\n", strerror(errno)); - - return timer_source->func(timer_source->base.data); + timer = wl_container_of(source, timer, base); + return timer->func(timer->base.data); } struct wl_event_source_interface timer_source_interface = { wl_event_source_timer_dispatch, }; +/** \endcond */ + /** Create a timer event source * * \param loop The event loop that will process the new source. @@ -260,16 +565,30 @@ wl_event_loop_add_timer(struct wl_event_loop *loop, { struct wl_event_source_timer *source; + if (wl_timer_heap_ensure_timerfd(&loop->timers) < 0) + return NULL; + source = malloc(sizeof *source); if (source == NULL) return NULL; source->base.interface = &timer_source_interface; - source->base.fd = timerfd_create(CLOCK_MONOTONIC, - TFD_CLOEXEC | TFD_NONBLOCK); + source->base.fd = -1; source->func = func; + source->base.loop = loop; + source->base.data = data; + wl_list_init(&source->base.link); + source->next_due = NULL; + source->deadline.tv_sec = 0; + source->deadline.tv_nsec = 0; + source->heap_idx = -1; - return add_source(loop, &source->base, WL_EVENT_READABLE, data); + if (wl_timer_heap_reserve(&loop->timers) < 0) { + free(source); + return NULL; + } + + return &source->base; } /** Arm or disarm a timer @@ -291,14 +610,50 @@ wl_event_loop_add_timer(struct wl_event_loop *loop, WL_EXPORT int wl_event_source_timer_update(struct wl_event_source *source, int ms_delay) { - struct itimerspec its; + struct wl_event_source_timer *tsource = + wl_container_of(source, tsource, base); + struct wl_timer_heap *timers = &tsource->base.loop->timers; - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - its.it_value.tv_sec = ms_delay / 1000; - its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000; - if (timerfd_settime(source->fd, 0, &its, NULL) < 0) - return -1; + if (ms_delay > 0) { + struct timespec deadline; + + clock_gettime(CLOCK_MONOTONIC, &deadline); + + deadline.tv_nsec += (ms_delay % 1000) * 1000000L; + deadline.tv_sec += ms_delay / 1000; + if (deadline.tv_nsec >= 1000000000L) { + deadline.tv_nsec -= 1000000000L; + deadline.tv_sec += 1; + } + + if (tsource->heap_idx == -1) { + wl_timer_heap_arm(timers, tsource, deadline); + } else if (time_lt(deadline, tsource->deadline)) { + tsource->deadline = deadline; + heap_sift_up(timers->data, tsource); + } else { + tsource->deadline = deadline; + heap_sift_down(timers->data, timers->active, tsource); + } + + if (tsource->heap_idx == 0) { + /* Only update the timerfd if the new deadline is + * the earliest */ + if (set_timer(timers->base.fd, deadline) < 0) + return -1; + } + } else { + if (tsource->heap_idx == -1) + return 0; + wl_timer_heap_disarm(timers, tsource); + + if (timers->active == 0) { + /* Only update the timerfd if this was the last + * active timer */ + if (clear_timer(timers->base.fd) < 0) + return -1; + } + } return 0; } @@ -483,6 +838,17 @@ wl_event_source_remove(struct wl_event_source *source) source->fd = -1; } + if (source->interface == &timer_source_interface && + source->fd != TIMER_REMOVED) { + /* Disarm the timer (and the loop's timerfd, if necessary), + * before removing its space in the loop timer heap */ + wl_event_source_timer_update(source, 0); + wl_timer_heap_unreserve(&loop->timers); + /* Set the fd field to to indicate that the timer should NOT + * be dispatched in `wl_event_loop_dispatch` */ + source->fd = TIMER_REMOVED; + } + wl_list_remove(&source->link); wl_list_insert(&loop->destroy_list, &source->link); @@ -534,6 +900,8 @@ wl_event_loop_create(void) wl_signal_init(&loop->destroy_signal); + wl_timer_heap_init(&loop->timers, loop); + return loop; } @@ -556,6 +924,7 @@ wl_event_loop_destroy(struct wl_event_loop *loop) wl_signal_emit(&loop->destroy_signal, loop); wl_event_loop_process_destroy_list(loop); + wl_timer_heap_release(&loop->timers); close(loop->epoll_fd); free(loop); } @@ -606,7 +975,7 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop) * * \param loop The event loop whose sources to wait for. * \param timeout The polling timeout in milliseconds. - * \return 0 for success, -1 for polling error. + * \return 0 for success, -1 for polling (or timer update) error. * * All the associated event sources are polled. This function blocks until * any event source delivers an event (idle sources excluded), or the timeout @@ -628,6 +997,7 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) struct epoll_event ep[32]; struct wl_event_source *source; int i, count; + bool has_timers = false; wl_event_loop_dispatch_idle(loop); @@ -635,6 +1005,22 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) if (count < 0) return -1; + for (i = 0; i < count; i++) { + source = ep[i].data.ptr; + if (source == &loop->timers.base) + has_timers = true; + } + + if (has_timers) { + /* Dispatch timer sources before non-timer sources, so that + * the non-timer sources can not cancel (by calling + * `wl_event_source_timer_update`) the dispatching of the timers + * (Note that timer sources also can't cancel pending non-timer + * sources, since epoll_wait has already been called) */ + if (wl_timer_heap_dispatch(&loop->timers) < 0) + return -1; + } + for (i = 0; i < count; i++) { source = ep[i].data.ptr; if (source->fd != -1) From 2f88814d9bb43b1463ee82a3cd5787b7b5735d5c Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Wed, 25 Dec 2019 20:35:14 -0500 Subject: [PATCH 0636/1152] event-loop-test: Add test to verify timer ordering The new test verifies that, for a set of timers and a short sequence of timer update calls, when the event loop is run the timer callbacks are run in the expected order. Signed-off-by: Manuel Stoeckl --- tests/event-loop-test.c | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index e9e636cb..cbeaf8eb 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -346,6 +346,64 @@ TEST(event_loop_timer_updates) wl_event_loop_destroy(loop); } +struct timer_order_data { + struct wl_event_source *source; + int *last_number; + int number; +}; + +static int +timer_order_callback(void *data) +{ + struct timer_order_data *tod = data; + + /* Check that the timers have the correct sequence */ + assert(tod->number == *tod->last_number + 2); + *tod->last_number = tod->number; + return 0; +} + +TEST(event_loop_timer_order) +{ + struct wl_event_loop *loop = wl_event_loop_create(); + struct timer_order_data order[20]; + int i, j; + int last = -1; + + /* Configure a set of timers so that only timers 1, 3, 5, ..., 19 + * (in that order) will be dispatched when the event loop is run */ + + for (i = 0; i < 20; i++) { + order[i].number = i; + order[i].last_number = &last; + order[i].source = + wl_event_loop_add_timer(loop, timer_order_callback, + &order[i]); + assert(order[i].source); + assert(wl_event_source_timer_update(order[i].source, 10) == 0); + } + + for (i = 0; i < 20; i++) { + /* Permute the order in which timers are updated, so as to + * more exhaustively test the underlying priority queue code */ + j = ((i + 3) * 17) % 20; + assert(wl_event_source_timer_update(order[j].source, j) == 0); + } + for (i = 0; i < 20; i += 2) { + assert(wl_event_source_timer_update(order[i].source, 0) == 0); + } + + /* Wait until all timers are due */ + usleep(MSEC_TO_USEC(21)); + wl_event_loop_dispatch(loop, 0); + assert(last == 19); + + for (i = 0; i < 20; i++) { + wl_event_source_remove(order[i].source); + } + wl_event_loop_destroy(loop); +} + struct timer_cancel_context { struct wl_event_source *timers[4]; struct timer_cancel_context *back_refs[4]; From d377ab9c077e8b1989385ae44aa6d8433e1a0825 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Jan 2020 19:00:33 +0100 Subject: [PATCH 0637/1152] protocol: add missing enums for wl_data_device_manager.dnd_action Signed-off-by: Simon Ser --- protocol/wayland.xml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 1f645ba0..f1d95c7a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -593,8 +593,10 @@ This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise. - - + + @@ -603,7 +605,8 @@ will be sent right after wl_data_device.enter, or anytime the source side changes its offered actions through wl_data_source.set_actions. - + @@ -644,7 +647,8 @@ final wl_data_offer.set_actions and wl_data_offer.accept requests must happen before the call to wl_data_offer.finish. - + @@ -741,7 +745,8 @@ wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error. - + @@ -797,7 +802,8 @@ Clients can trigger cursor surface changes from this point, so they reflect the current action. - + From 75e644c23ded2ef798fa31383c51afcf305cc9cb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jan 2020 15:18:48 +0100 Subject: [PATCH 0638/1152] build: bump to version 1.17.91 for the alpha release --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index eb859771..0a7d16c0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [17]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index be2129cf..2bd4f0e7 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.17.90', + version: '1.17.91', license: 'MIT', meson_version: '>= 0.47.0', default_options: [ From 501cad11888a15cafb669fc0fd881da50de72cc4 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 22 Jan 2020 13:40:42 +0100 Subject: [PATCH 0639/1152] Remove unused HAVE_CONFIG_H define in meson Signed-off-by: Emmanuel Gil Peyrot --- meson.build | 2 -- 1 file changed, 2 deletions(-) diff --git a/meson.build b/meson.build index 2bd4f0e7..6fb12402 100644 --- a/meson.build +++ b/meson.build @@ -70,8 +70,6 @@ configure_file( configuration: config_h, ) -add_project_arguments([ '-DHAVE_CONFIG_H' ], language: 'c') - pkgconfig = import('pkgconfig') wayland_protocol_xml = files('protocol/wayland.xml') From 8e2199644e4fc34ebf46ea65b7598517eaa69f18 Mon Sep 17 00:00:00 2001 From: Ihor Antonov Date: Fri, 17 Jan 2020 21:13:12 -0800 Subject: [PATCH 0640/1152] os: fallback for unsupported posix_fallocate Some filesystems do not support fallocate and return EOPNOTSUPP. On musl-based distros libwayland-cursor exits abruptly which causes the application to crash. Unlike glibc, musl does not provide a fallback mechanism for handling unsupported fallocate. Instead, musl developers argue that application should handle the case of unsupported system call. This commit allows falback to ftruncate in case when EOPNOTSUPP was recieved. Signed-off-by: Ihor Antonov --- cursor/os-compatibility.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 9008755d..6f5b39f4 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -156,19 +156,24 @@ os_create_anonymous_file(off_t size) } #ifdef HAVE_POSIX_FALLOCATE + /* + * Filesystems that do support fallocate will return EOPNOTSUPP. + * In this case we need to fall back to ftruncate + */ ret = posix_fallocate(fd, 0, size); - if (ret != 0) { + if (ret == 0) { + return fd; + } else if (ret != EOPNOTSUPP) { close(fd); errno = ret; return -1; } -#else +#endif ret = ftruncate(fd, size); if (ret < 0) { close(fd); return -1; } -#endif return fd; } From 96a8465e38cd5debd438d9463d54c8683751923f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 Sep 2019 11:10:15 +0300 Subject: [PATCH 0641/1152] tests: fix memory leak in proxy-test When running tests with ASan, proxy-test fails at the proxy_tag test: ==27843==ERROR: LeakSanitizer: detected memory leaks Direct leak of 32 byte(s) in 1 object(s) allocated from: #0 0x7f65a732dada in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:144 #1 0x7f65a71cb3ea in wl_display_add_protocol_logger src/wayland-server.c:1813 #2 0x557c640c0980 in proxy_tag tests/proxy-test.c:104 #3 0x557c640c1159 in run_test tests/test-runner.c:153 #4 0x557c640c1e2e in main tests/test-runner.c:337 #5 0x7f65a6ea0ee2 in __libc_start_main (/usr/lib/libc.so.6+0x26ee2) SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s). Destroying the logger fixes the leak. Signed-off-by: Simon Ser Fixes: 493ab79bd2cd ("proxy: Add API to tag proxy objects") --- tests/proxy-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/proxy-test.c b/tests/proxy-test.c index d91a73d9..c09468d7 100644 --- a/tests/proxy-test.c +++ b/tests/proxy-test.c @@ -129,6 +129,7 @@ TEST(proxy_tag) assert(client.callback_count == 2); + wl_protocol_logger_destroy(logger); wl_display_disconnect(client.display); wl_event_loop_dispatch(server.loop, 100); From 367d2985f3242d12c16a4f9074254584a8739d1f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jan 2020 22:02:25 +0100 Subject: [PATCH 0642/1152] build: bump to version 1.17.92 for the beta release --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 0a7d16c0..6741f4b8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [17]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index 6fb12402..ea01708f 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.17.91', + version: '1.17.92', license: 'MIT', meson_version: '>= 0.47.0', default_options: [ From 3d1c6c6f685748276a33dc442bb05ec5f0ac47a1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 4 Feb 2020 15:15:20 +0100 Subject: [PATCH 0643/1152] autotools: add Meson files to EXTRA_DIST This allows users to build Wayland with Meson from an autotools-generated release tarball. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/issues/141 --- Makefile.am | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 928874c1..cc873922 100644 --- a/Makefile.am +++ b/Makefile.am @@ -316,7 +316,23 @@ EXTRA_DIST += tests/scanner-test.sh \ tests/data/small-code-core.c \ tests/data/small-client-core.h \ tests/data/small-server-core.h \ - tests/data/small-private-code.c + tests/data/small-private-code.c \ + meson.build \ + meson_options.txt \ + cursor/meson.build \ + doc/meson.build \ + doc/doxygen/mainpage.dox \ + doc/doxygen/meson.build \ + doc/doxygen/gen-doxygen.py \ + doc/doxygen/xml/meson.build \ + doc/doxygen/xml/Client/meson.build \ + doc/doxygen/xml/Server/meson.build \ + doc/man/meson.build \ + doc/publican/meson.build \ + doc/publican/sources/meson.build \ + egl/meson.build \ + src/meson.build \ + tests/meson.build tests/scanner-test.sh: $(top_builddir)/wayland-scanner From 57f17de0ec0a2bfe8a4cd9bc0be6ab0a06c6fbfd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 5 Feb 2020 00:32:03 +0100 Subject: [PATCH 0644/1152] build: bump to version 1.17.93 for the RC1 release --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6741f4b8..f7a668ad 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [17]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index ea01708f..b81a2029 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.17.92', + version: '1.17.93', license: 'MIT', meson_version: '>= 0.47.0', default_options: [ From eb1339edd398b9f5328816931e585db4229aa132 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 12 Feb 2020 00:45:15 +0100 Subject: [PATCH 0645/1152] build: bump to version 1.18.0 for the official release --- configure.ac | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index f7a668ad..dda5e48c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [17]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [18]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index b81a2029..5632f4e6 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.17.93', + version: '1.18.0', license: 'MIT', meson_version: '>= 0.47.0', default_options: [ From c57157e3906c5921fb166e17475b36e2ace6a9eb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 12 Feb 2020 00:55:32 +0100 Subject: [PATCH 0646/1152] build: re-open master for regular development --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index dda5e48c..fe035398 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [18]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index 5632f4e6..26b084f7 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.18.0', + version: '1.18.90', license: 'MIT', meson_version: '>= 0.47.0', default_options: [ From 0fc00fff3015edb70b865f126dc8f4c258fe2f56 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 15 Feb 2020 02:03:45 +0000 Subject: [PATCH 0647/1152] meson/tests: add missing dependencies on protocol headers In file included from ../tests/connection-test.c:43: In file included from ../tests/test-compositor.h:30: ../src/wayland-client.h:40:10: fatal error: 'wayland-client-protocol.h' file not found #include "wayland-client-protocol.h" ^~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/display-test.c:45: In file included from ../src/wayland-server.h:104: src/wayland-server-protocol.h:4454:2: error: unterminated /* comment /** ^ In file included from ../tests/cpp-compile-test.cpp:2: In file included from src/wayland-server-protocol.h:8: In file included from ../src/wayland-server.h:104: src/wayland-server-protocol.h:3:2: error: unterminated conditional directive #ifndef WAYLAND_SERVER_PROTOCOL_H ^ ../tests/headers-protocol-test.c:33:2: error: including wayland-server-protocol.h did not include wayland-server.h! #error including wayland-server-protocol.h did not include wayland-server.h! ^ In file included from ../tests/headers-protocol-test.c:26: In file included from src/wayland-client-protocol.h:8: In file included from ../src/wayland-client.h:40: src/wayland-client-protocol.h:1358:2: error: unterminated conditional directive #ifndef WL_SHM_FORMAT_ENUM ^ In file included from ../tests/protocol-logger-test.c:34: In file included from ../src/wayland-client.h:40: src/wayland-client-protocol.h:2613:1: error: unterminated /* comment /** ^ ../tests/resources-test.c:49:36: error: use of undeclared identifier 'wl_seat_interface' res = wl_resource_create(client, &wl_seat_interface, 4, 0); ^ --- tests/meson.build | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/meson.build b/tests/meson.build index c28a2a39..f1af7b4a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -69,7 +69,7 @@ test( executable( 'cpp-compile-test', 'cpp-compile-test.cpp', - wayland_server_protocol_core_h, + wayland_server_protocol_h, include_directories: src_inc ) ) @@ -91,17 +91,25 @@ tests = { 'array-test': [], 'client-test': [ wayland_server_protocol_h ], 'display-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, tests_server_protocol_h, tests_client_protocol_c, tests_protocol_c, ], - 'connection-test': [ wayland_server_protocol_h ], + 'connection-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], 'event-loop-test': [ wayland_server_protocol_h ], 'fixed-test': [], 'interface-test': [ wayland_client_protocol_h ], 'list-test': [], 'map-test': [], - 'sanity-test' : [ wayland_server_protocol_h ], + 'sanity-test' : [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], 'socket-test': [ wayland_client_protocol_h, wayland_server_protocol_h, @@ -116,7 +124,7 @@ tests = { files('../src/wayland-server.c'), wayland_server_protocol_h, ], - 'resources-test': [ wayland_server_protocol_core_h ], + 'resources-test': [ wayland_server_protocol_h ], 'message-test': [ wayland_client_protocol_h, wayland_server_protocol_h, @@ -126,14 +134,16 @@ tests = { wayland_server_protocol_h, ], 'protocol-logger-test': [ - wayland_server_protocol_core_h, - wayland_client_protocol_core_h, + wayland_client_protocol_h, + wayland_server_protocol_h, ], 'headers-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, 'headers-protocol-test.c', - 'headers-protocol-core-test.c', - wayland_server_protocol_core_h, wayland_client_protocol_core_h, + wayland_server_protocol_core_h, + 'headers-protocol-core-test.c', ], 'os-wrappers-test': [], } From 1283d54dac97216fb7bf099b864a6728043e2d8d Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 15 Feb 2020 15:15:00 +0000 Subject: [PATCH 0648/1152] cursor: posix_fallocate may fail with EINVAL if not supported ZFS on FreeBSD >= 12.0 returns EINVAL, see https://svnweb.freebsd.org/changeset/base/325320 Signed-off-by: Jan Beich --- cursor/os-compatibility.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 6f5b39f4..002bb5cd 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -157,13 +157,13 @@ os_create_anonymous_file(off_t size) #ifdef HAVE_POSIX_FALLOCATE /* - * Filesystems that do support fallocate will return EOPNOTSUPP. - * In this case we need to fall back to ftruncate + * Filesystems that do support fallocate will return EINVAL or + * EOPNOTSUPP. In this case we need to fall back to ftruncate */ ret = posix_fallocate(fd, 0, size); if (ret == 0) { return fd; - } else if (ret != EOPNOTSUPP) { + } else if (ret != EINVAL && ret != EOPNOTSUPP) { close(fd); errno = ret; return -1; From 3a3dd0820de331d560af954bf9d786c1256ec577 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 15 Feb 2020 15:16:51 +0000 Subject: [PATCH 0649/1152] cursor: ignore posix_fallocate in shm_pool_resize if not supported by FS Signed-off-by: Jan Beich --- cursor/wayland-cursor.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index d40c5c8e..ca5be8dd 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -83,15 +83,19 @@ err_free: static int shm_pool_resize(struct shm_pool *pool, int size) { - if (ftruncate(pool->fd, size) < 0) - return 0; - #ifdef HAVE_POSIX_FALLOCATE + /* + * Filesystems that do support fallocate will return EINVAL or + * EOPNOTSUPP. In this case we need to fall back to ftruncate + */ errno = posix_fallocate(pool->fd, 0, size); - if (errno != 0) + if (errno != 0 && errno != EINVAL && errno != EOPNOTSUPP) return 0; #endif + if (ftruncate(pool->fd, size) < 0) + return 0; + wl_shm_pool_resize(pool->pool, size); munmap(pool->data, pool->size); From 230885ebb40b35c68a3b88a649f449afa344ec28 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 16 Feb 2020 05:54:33 +0000 Subject: [PATCH 0650/1152] cursor/os-compatibility: move resizing into a separate function Signed-off-by: Jan Beich --- cursor/os-compatibility.c | 38 +++++++++++++++++++++----------------- cursor/os-compatibility.h | 3 +++ cursor/wayland-cursor.c | 12 +----------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 002bb5cd..9eac2297 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -119,7 +119,6 @@ os_create_anonymous_file(off_t size) const char *path; char *name; int fd; - int ret; #ifdef HAVE_MEMFD_CREATE fd = memfd_create("wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING); @@ -155,25 +154,30 @@ os_create_anonymous_file(off_t size) return -1; } -#ifdef HAVE_POSIX_FALLOCATE - /* - * Filesystems that do support fallocate will return EINVAL or - * EOPNOTSUPP. In this case we need to fall back to ftruncate - */ - ret = posix_fallocate(fd, 0, size); - if (ret == 0) { - return fd; - } else if (ret != EINVAL && ret != EOPNOTSUPP) { - close(fd); - errno = ret; - return -1; - } -#endif - ret = ftruncate(fd, size); - if (ret < 0) { + if (os_resize_anonymous_file(fd, size) < 0) { close(fd); return -1; } return fd; } + +int +os_resize_anonymous_file(int fd, off_t size) +{ +#ifdef HAVE_POSIX_FALLOCATE + /* + * Filesystems that do support fallocate will return EINVAL or + * EOPNOTSUPP. In this case we need to fall back to ftruncate + */ + errno = posix_fallocate(fd, 0, size); + if (errno == 0) + return 0; + else if (errno != EINVAL && errno != EOPNOTSUPP) + return -1; +#endif + if (ftruncate(fd, size) < 0) + return -1; + + return 0; +} diff --git a/cursor/os-compatibility.h b/cursor/os-compatibility.h index d0e69acd..fdfeb78b 100644 --- a/cursor/os-compatibility.h +++ b/cursor/os-compatibility.h @@ -31,4 +31,7 @@ int os_create_anonymous_file(off_t size); +int +os_resize_anonymous_file(int fd, off_t size); + #endif /* OS_COMPATIBILITY_H */ diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index ca5be8dd..4e2dc502 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -83,17 +83,7 @@ err_free: static int shm_pool_resize(struct shm_pool *pool, int size) { -#ifdef HAVE_POSIX_FALLOCATE - /* - * Filesystems that do support fallocate will return EINVAL or - * EOPNOTSUPP. In this case we need to fall back to ftruncate - */ - errno = posix_fallocate(pool->fd, 0, size); - if (errno != 0 && errno != EINVAL && errno != EOPNOTSUPP) - return 0; -#endif - - if (ftruncate(pool->fd, size) < 0) + if (os_resize_anonymous_file(pool->fd, size) < 0) return 0; wl_shm_pool_resize(pool->pool, size); From ef40f82ac1b90f49af0f147d958a558cc980cb8b Mon Sep 17 00:00:00 2001 From: Tomek Bury Date: Mon, 24 Feb 2020 11:02:44 +0000 Subject: [PATCH 0651/1152] util: fix compiler warning conversion to 'wl_fixed_t {aka int}' from 'int64_t {aka long int}' may alter its value [-Werror=conversion] --- src/wayland-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 2115f5c7..79977783 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -640,7 +640,7 @@ wl_fixed_from_double(double d) u.d = d + (3LL << (51 - 8)); - return u.i; + return (wl_fixed_t)u.i; } /** From 8d5fadad47aad420b0d83fffc8ad573766a9c75e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 26 Feb 2020 18:30:57 +0100 Subject: [PATCH 0652/1152] protocol: add invalid_size error to wl_surface This allows the compositor to send an error when the client submits a buffer whose size is not divisible by the buffer scale. Previously, the protocol said it was a client error but didn't specify any error code. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/issues/145 --- protocol/wayland.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f1d95c7a..d3e54ee7 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1378,6 +1378,7 @@ + @@ -1392,8 +1393,9 @@ The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the - inverse buffer_scale. This means that the supplied buffer - must be an integer multiple of the buffer_scale. + inverse buffer_scale. This means that at commit time the supplied + buffer size must be an integer multiple of the buffer_scale. If + that's not the case, an invalid_size error is sent. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper From 5ddb8dff878f3addd349bf58860cb6fad0a013ce Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Fri, 6 Mar 2020 10:04:53 -0800 Subject: [PATCH 0653/1152] meson: Require wayland-scanner of a matching version We have always built libwayland with the scanner from the same build so that the generated code and installed headers are exactly up-to-date with the libwayland version. If libwayland was to use a scanner later than itself, the scanner might do things that are not available in the libwayland at hand, leading to a broken build or a broken library (headers). Signed-off-by: Matt Turner --- src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index 3e8c9bfb..cf92321f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -55,7 +55,7 @@ pkgconfig.generate( ) if meson.is_cross_build() - scanner_dep = dependency('wayland-scanner', native: true, version: '>=1.14.0') + scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version()) wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) else wayland_scanner_for_build = wayland_scanner From 618663c791092bb82dc0a153a4a2fe97582a54bc Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Thu, 5 Mar 2020 12:04:36 -0800 Subject: [PATCH 0654/1152] meson: Add option to control building wayland-scanner Wayland requires a binary, wayland-scanner, to be run during the build process. For any configuration other than native builds (including cross compiling and even 32-bit x86 builds on an x86-64 build machine) Wayland's build process builds and uses its own wayland-scanner. For any builds using a cross file, wayland-scanner is built for the host machine and therefore cannot be executed during the build of the Wayland libraries. Instead builds using a cross file must execute the build machine's wayland-scanner (typically /usr/bin/wayland-scanner). As such, to build Wayland's libraries for a non-native ABI a package manager must build and install /usr/bin/wayland-scanner first. But then the build for the native ABI then rebuilds wayland-scanner itself and doesn't use the system's, and worse, wants to install its own, which conflicts with the /usr/bin/wayland-scanner already installed! So, add the -Dscanner=... option to control whether to install wayland-scanner. Signed-off-by: Matt Turner --- meson.build | 27 +++++++-------- meson_options.txt | 4 +++ src/meson.build | 85 ++++++++++++++++++++++++++++------------------- tests/meson.build | 22 ++++++------ 4 files changed, 80 insertions(+), 58 deletions(-) diff --git a/meson.build b/meson.build index 26b084f7..540dee83 100644 --- a/meson.build +++ b/meson.build @@ -84,19 +84,20 @@ if get_option('libraries') subdir('cursor') subdir('egl') subdir('tests') + if get_option('documentation') + subdir('doc') + endif endif -if get_option('documentation') - subdir('doc') +if get_option('scanner') + install_data([ + 'wayland-scanner.mk', + 'protocol/wayland.xml', + 'protocol/wayland.dtd', + ]) + + install_data( + [ 'wayland-scanner.m4' ], + install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'aclocal'), + ) endif - -install_data([ - 'wayland-scanner.mk', - 'protocol/wayland.xml', - 'protocol/wayland.dtd', -]) - -install_data( - [ 'wayland-scanner.m4' ], - install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'aclocal'), -) diff --git a/meson_options.txt b/meson_options.txt index 76314f79..de588d13 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,6 +2,10 @@ option('libraries', description: 'Compile Wayland libraries', type: 'boolean', value: 'true') +option('scanner', + description: 'Compile wayland-scanner binary', + type: 'boolean', + value: 'true') option('documentation', description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)', type: 'boolean', diff --git a/src/meson.build b/src/meson.build index cf92321f..a61d40f6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,12 +4,6 @@ wayland_version_h.set('WAYLAND_VERSION', meson.project_version()) wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int()) wayland_version_h.set('WAYLAND_VERSION_MINOR', wayland_version[1].to_int()) wayland_version_h.set('WAYLAND_VERSION_MICRO', wayland_version[2].to_int()) -configure_file( - input: 'wayland-version.h.in', - output: 'wayland-version.h', - configuration: wayland_version_h, - install_dir: join_paths(get_option('prefix'), get_option('includedir')) -) wayland_util = static_library( 'wayland-util', @@ -21,40 +15,48 @@ wayland_util_dep = declare_dependency( include_directories: include_directories('.') ) -# wayland-scanner +if get_option('scanner') + # wayland-scanner -configure_file( - input: '../protocol/wayland.dtd', - output: 'wayland.dtd.embed', - copy: true -) + configure_file( + input: 'wayland-version.h.in', + output: 'wayland-version.h', + configuration: wayland_version_h, + ) -wayland_scanner_sources = [ 'scanner.c', 'dtddata.S' ] -wayland_scanner_includes = [ root_inc, protocol_inc ] + configure_file( + input: '../protocol/wayland.dtd', + output: 'wayland.dtd.embed', + copy: true + ) -wayland_scanner = executable( - 'wayland-scanner', - wayland_scanner_sources, - c_args: [ '-include', 'config.h' ], - include_directories: wayland_scanner_includes, - dependencies: [ scanner_deps, wayland_util_dep, ], - install: true -) + wayland_scanner_sources = [ 'scanner.c', 'dtddata.S' ] + wayland_scanner_includes = [ root_inc, protocol_inc ] -pkgconfig.generate( - name: 'Wayland Scanner', - description: 'Wayland scanner', - version: meson.project_version(), - variables: [ - 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), - 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()), - 'bindir=' + join_paths('${prefix}', get_option('bindir')), - 'wayland_scanner=${bindir}/wayland-scanner' - ], - filebase: 'wayland-scanner' -) + wayland_scanner = executable( + 'wayland-scanner', + wayland_scanner_sources, + c_args: [ '-include', 'config.h' ], + include_directories: wayland_scanner_includes, + dependencies: [ scanner_deps, wayland_util_dep, ], + install: true + ) -if meson.is_cross_build() + pkgconfig.generate( + name: 'Wayland Scanner', + description: 'Wayland scanner', + version: meson.project_version(), + variables: [ + 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), + 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()), + 'bindir=' + join_paths('${prefix}', get_option('bindir')), + 'wayland_scanner=${bindir}/wayland-scanner' + ], + filebase: 'wayland-scanner' + ) +endif + +if meson.is_cross_build() or not get_option('scanner') scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version()) wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) else @@ -62,6 +64,19 @@ else endif if get_option('libraries') + # wayland libraries + + # Duplicated inside the "if get_option('scanner')" block above since we + # still need the wayland-version.h to build the scanner, but do not want + # to install it. Meson 0.50 adds "install: bool" which will let us + # deduplicate this block. + configure_file( + input: 'wayland-version.h.in', + output: 'wayland-version.h', + configuration: wayland_version_h, + install_dir: join_paths(get_option('prefix'), get_option('includedir')) + ) + mathlib_dep = cc.find_library('m', required: false) threads_dep = dependency('threads', required: false) diff --git a/tests/meson.build b/tests/meson.build index f1af7b4a..224f48dd 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -76,16 +76,18 @@ test( sed_path = find_program('sed').path() -test( - 'scanner-test', - find_program('scanner-test.sh'), - env: [ - 'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()), - 'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()), - 'SED=@0@'.format(sed_path), - 'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()), - ], -) +if get_option('scanner') + test( + 'scanner-test', + find_program('scanner-test.sh'), + env: [ + 'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()), + 'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()), + 'SED=@0@'.format(sed_path), + 'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()), + ], + ) +endif tests = { 'array-test': [], From d840681707287df9a06bb427caab065b2e50515d Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Mon, 16 Mar 2020 16:43:57 -0700 Subject: [PATCH 0655/1152] .gitlab-ci.yml: Switch from Stretch to Buster Stretch is old-stable and will reach end of life this year. buster-backports has newer Meson available, so switching to Buster will allow us to bump the Meson requirements. Signed-off-by: Matt Turner --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c665ef6b..1037fee0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: debian:stretch +image: debian:buster stages: - build @@ -9,9 +9,9 @@ before_script: - echo '#!/bin/sh' > /usr/sbin/policy-rc.d - echo 'exit 101' >> /usr/sbin/policy-rc.d - chmod +x /usr/sbin/policy-rc.d - - echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/sources.list + - echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list - apt-get update - - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson/stretch-backports + - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson/buster-backports build-native-autotools: stage: build From 9f9e971f56e20fd4347b5af790f223909c7fb88e Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Mon, 16 Mar 2020 16:46:00 -0700 Subject: [PATCH 0656/1152] meson: Raise requirement to meson >= 0.52.1 Many new and valuable features were added between Meson 0.49 and 0.52.1. We would like to use some of them. Signed-off-by: Matt Turner --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 540dee83..b67b101b 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'wayland', 'c', 'cpp', version: '1.18.90', license: 'MIT', - meson_version: '>= 0.47.0', + meson_version: '>= 0.52.1', default_options: [ 'warning_level=2', 'buildtype=debugoptimized' From 6d4497371014cacbf0dc4ed9983fd6617ec25c9a Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Mon, 16 Mar 2020 16:47:05 -0700 Subject: [PATCH 0657/1152] meson: Deduplicate generation of wayland-version.h Signed-off-by: Matt Turner --- src/meson.build | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/meson.build b/src/meson.build index a61d40f6..2d1485c6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,6 +4,14 @@ wayland_version_h.set('WAYLAND_VERSION', meson.project_version()) wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int()) wayland_version_h.set('WAYLAND_VERSION_MINOR', wayland_version[1].to_int()) wayland_version_h.set('WAYLAND_VERSION_MICRO', wayland_version[2].to_int()) +configure_file( + input: 'wayland-version.h.in', + output: 'wayland-version.h', + configuration: wayland_version_h, + install: get_option('libraries'), + install_dir: join_paths(get_option('prefix'), get_option('includedir')) +) + wayland_util = static_library( 'wayland-util', @@ -18,12 +26,6 @@ wayland_util_dep = declare_dependency( if get_option('scanner') # wayland-scanner - configure_file( - input: 'wayland-version.h.in', - output: 'wayland-version.h', - configuration: wayland_version_h, - ) - configure_file( input: '../protocol/wayland.dtd', output: 'wayland.dtd.embed', @@ -66,17 +68,6 @@ endif if get_option('libraries') # wayland libraries - # Duplicated inside the "if get_option('scanner')" block above since we - # still need the wayland-version.h to build the scanner, but do not want - # to install it. Meson 0.50 adds "install: bool" which will let us - # deduplicate this block. - configure_file( - input: 'wayland-version.h.in', - output: 'wayland-version.h', - configuration: wayland_version_h, - install_dir: join_paths(get_option('prefix'), get_option('includedir')) - ) - mathlib_dep = cc.find_library('m', required: false) threads_dep = dependency('threads', required: false) From 25f216d97f7311e61498963c49245169f9b23e18 Mon Sep 17 00:00:00 2001 From: Ricardo Quesada Date: Tue, 7 Apr 2020 10:06:19 -0700 Subject: [PATCH 0658/1152] README with upadated compile instructions This commit updates the README build & install instructions. It replaces that obsolete "autogen && make" with "meson && ninja" Signed-off-by: Ricardo Quesada --- README | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README b/README index 3ae9f0fc..ad06dce6 100644 --- a/README +++ b/README @@ -26,9 +26,8 @@ they don't have many dependencies: $ git clone https://gitlab.freedesktop.org/wayland/wayland $ cd wayland - $ ./autogen.sh --prefix=PREFIX - $ make - $ make install + $ meson build/ --prefix=PREFIX + $ ninja -C build/ install where PREFIX is where you want to install the libraries. See https://wayland.freedesktop.org for more complete build instructions From 24ca1a5b578a63b731127c115f2cc6ea50c25686 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Apr 2020 19:49:12 +0200 Subject: [PATCH 0659/1152] client: improve wl_display_connect docs Add a paragraph about WAYLAND_SOCKET and describe what happens when the display name is a relative path. Signed-off-by: Simon Ser --- src/wayland-client.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 53585000..21d46067 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1113,6 +1113,13 @@ wl_display_connect_to_fd(int fd) * its value will be replaced with the WAYLAND_DISPLAY environment * variable if it is set, otherwise display "wayland-0" will be used. * + * If WAYLAND_SOCKET is set, it's interpreted as a file descriptor number + * referring to an already opened socket. In this case, the socket is used + * as-is and \c name is ignored. + * + * If \c name is a relative path, then the socket is opened relative to + * the XDG_RUNTIME_DIR directory. + * * If \c name is an absolute path, then that path is used as-is for * the location of the socket at which the Wayland server is listening; * no qualification inside XDG_RUNTIME_DIR is attempted. From 7d3d2ae31053b741b7dd30918e023c364413c25a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Apr 2020 19:50:52 +0200 Subject: [PATCH 0660/1152] doc/man: remove manually written man pages There is only one page written. Having manually-written man pages duplicates information with doc comments. Besides, man pages are already generated by Doxygen. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/156 --- Makefile.am | 1 - configure.ac | 1 - doc/Makefile.am | 2 +- doc/man/Makefile.am | 49 --------------- doc/man/meson.build | 46 -------------- doc/man/wl_display_connect.xml | 112 --------------------------------- doc/meson.build | 1 - 7 files changed, 1 insertion(+), 211 deletions(-) delete mode 100644 doc/man/Makefile.am delete mode 100644 doc/man/meson.build delete mode 100644 doc/man/wl_display_connect.xml diff --git a/Makefile.am b/Makefile.am index cc873922..b9438b7e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -327,7 +327,6 @@ EXTRA_DIST += tests/scanner-test.sh \ doc/doxygen/xml/meson.build \ doc/doxygen/xml/Client/meson.build \ doc/doxygen/xml/Server/meson.build \ - doc/man/meson.build \ doc/publican/meson.build \ doc/publican/sources/meson.build \ egl/meson.build \ diff --git a/configure.ac b/configure.ac index fe035398..ace83b2e 100644 --- a/configure.ac +++ b/configure.ac @@ -190,7 +190,6 @@ AC_CONFIG_FILES([Makefile doc/Makefile doc/publican/Makefile doc/doxygen/Makefile - doc/man/Makefile egl/wayland-egl.pc egl/wayland-egl-backend.pc src/wayland-server-uninstalled.pc diff --git a/doc/Makefile.am b/doc/Makefile.am index 1efd3e28..0b1c4f20 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1 +1 @@ -SUBDIRS = doxygen publican man +SUBDIRS = doxygen publican diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am deleted file mode 100644 index 4e6365cf..00000000 --- a/doc/man/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -# -# This generates man-pages out of the Docbook XML files. Simply add your files -# to the $MANPAGES array. If aliases are created, please add them to the -# MANPAGES_ALIASES array so they get installed correctly. -# - -MANPAGES = \ - wl_display_connect.3 -MANPAGES_ALIASES = \ - wl_display_connect_to_fd.3 - -XML_FILES = \ - ${patsubst %.1,%.xml,${patsubst %.3,%.xml,${patsubst %.5,%.xml,${patsubst %.7,%.xml,$(MANPAGES)}}}} -CLEANFILES = -EXTRA_DIST = $(XML_FILES) - -if HAVE_XSLTPROC - -CLEANFILES += $(MANPAGES) $(MANPAGES_ALIASES) -EXTRA_DIST += $(MANPAGES) $(MANPAGES_ALIASES) -dist_man_MANS = $(MANPAGES) $(MANPAGES_ALIASES) - -XSLTPROC_FLAGS = \ - --stringparam man.authors.section.enabled 0 \ - --stringparam man.copyright.section.enabled 0 \ - --stringparam funcsynopsis.style ansi \ - --stringparam man.output.quietly 1 \ - --nonet - -XSLTPROC_PROCESS_MAN = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(DOCS_STYLESHEET) $< && \ - $(SED) -i -e 's/^\.so \(.*\)\.\(.\)$$/\.so man\2\/\1\.\2/' $(MANPAGES_ALIASES) - -%.1: %.xml - $(XSLTPROC_PROCESS_MAN) - -%.3: %.xml - $(XSLTPROC_PROCESS_MAN) - -%.5: %.xml - $(XSLTPROC_PROCESS_MAN) - -%.7: %.xml - $(XSLTPROC_PROCESS_MAN) - -wl_display_connect_to_fd.3: wl_display_connect.3 - -endif # HAVE_XSLTPROC diff --git a/doc/man/meson.build b/doc/man/meson.build deleted file mode 100644 index 0fd4cec7..00000000 --- a/doc/man/meson.build +++ /dev/null @@ -1,46 +0,0 @@ -man_pages = [ - { - 'section': '3', - 'xml': 'wl_display_connect.xml', - 'name': 'wl_display_connect', - 'alias': 'wl_display_connect_to_fd', - } -] - -xsltproc_opts = [ - '--nonet', - '--stringparam', 'man.authors.section.enabled', '0', - '--stringparam', 'man.copyright.section.enabled', '0', - '--stringparam', 'funcsynopsis.style', 'ansi', - '--stringparam', 'man.output.quietly', '1', -] - -foreach page: man_pages - section_number = page['section'] - xml_input = page['xml'] - name = page['name'] - alias = page.get('alias', '') - - man_output = name + '.' + section_number - if alias != '' - alias_output = alias + '.' + section_number - else - alias_output = [] - endif - - man_page = custom_target( - name + '-man', - command: [ - xsltproc, - xsltproc_opts, - '-o', '@OUTPUT0@', - manpage_xsl, - '@INPUT@', - ], - input: xml_input, - output: [ man_output, alias_output ], - install: true, - install_dir: join_paths(get_option('prefix'), get_option('mandir'), 'man' + section_number), - build_by_default: true, - ) -endforeach diff --git a/doc/man/wl_display_connect.xml b/doc/man/wl_display_connect.xml deleted file mode 100644 index dab4ddba..00000000 --- a/doc/man/wl_display_connect.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - wl_display_connect - wayland-client - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - wl_display_connect - 3 - - - - wl_display_connect - wl_display_connect_to_fd - Connect to a Wayland socket - - - - - - #include <wayland-client.h> - - - struct wl_display *wl_display_connect - const char *name - - - - struct wl_display *wl_display_connect_to_fd - int fd - - - - - - - Description - wl_display_connect connects to a Wayland socket - that was previously opened by a Wayland server. The server socket must - be placed in XDG_RUNTIME_DIR when WAYLAND_DISPLAY - (or name, see below) is a simple name, for this - function to find it. The server socket is also allowed to exist at an - arbitrary path; usage details follow. See below for compatibility issue - details. - - The name argument specifies the name of - the socket or NULL to use the default (which is - "wayland-0"). The environment variable - WAYLAND_DISPLAY replaces the default value. - - If name is an absolute path, then that path is used - as the Wayland socket to which the connection is attempted. Note that - in combination with the default-value behavior described above, this - implies that setting WAYLAND_DISPLAY to an absolute - path will implicitly cause name to take on that - absolute path if name is NULL. - - If WAYLAND_SOCKET is set, this function behaves like - wl_display_connect_to_fd with the file-descriptor - number taken from the environment variable. - - Support for interpreting WAYLAND_DISPLAY as an - absolute path is a change in behavior compared to - wl_display_connect's behavior in versions - 1.14 and older of Wayland. It is no longer guaranteed in versions - 1.15 and higher that the Wayland socket chosen is equivalent to - manually constructing a socket pathname by concatenating - XDG_RUNTIME_DIR and WAYLAND_DISPLAY. - Manual construction of the socket path must account for the - possibility that WAYLAND_DISPLAY contains an absolute - path. - - wl_display_connect_to_fd connects to a Wayland - socket with an explicit file-descriptor. The file-descriptor is passed - as argument fd. - - - - Return Value - wl_display_connect and - wl_display_connect_to_fd return a new display - context object or NULL on failure. errno is set - correspondingly. - - - - See Also - - wayland-client7, - wl_display_disconnect3, - wl_display_iterate3 - - - diff --git a/doc/meson.build b/doc/meson.build index 0b46f48c..f74b6b1b 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -34,5 +34,4 @@ publican_install_prefix = join_paths( publican_html_dir = 'html' subdir('doxygen') -subdir('man') subdir('publican') From cc8b6aa3d937dda055cb25fdbec55d0afb6be2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Tue, 21 Apr 2020 12:47:56 +0200 Subject: [PATCH 0661/1152] scanner: Guard interface declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to include client and server headers in the same file fixing warnings like In file included from ../subprojects/wlroots/include/wlr/types/wlr_layer_shell_v1.h:16, from ../src/desktop.h:16, from ../src/server.h:13, from ../tests/testlib.c:8: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-protocol.h:80:34: warning: redundant redeclaration of ‘zwlr_layer_shell_v1_interface’ [-Wredundant-decls] 80 | extern const struct wl_interface zwlr_layer_shell_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/testlib.h:8, from ../tests/testlib.c:7: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-client-protocol.h:77:34: note: previous declaration of ‘zwlr_layer_shell_v1_interface’ was here 77 | extern const struct wl_interface zwlr_layer_shell_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../subprojects/wlroots/include/wlr/types/wlr_layer_shell_v1.h:16, from ../src/desktop.h:16, from ../src/server.h:13, from ../tests/testlib.c:8: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-protocol.h:106:34: warning: redundant redeclaration of ‘zwlr_layer_surface_v1_interface’ [-Wredundant-decls] 106 | extern const struct wl_interface zwlr_layer_surface_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/testlib.h:8, from ../tests/testlib.c:7: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-client-protocol.h:103:34: note: previous declaration of ‘zwlr_layer_surface_v1_interface’ was here 103 | extern const struct wl_interface zwlr_layer_surface_v1_interface; Signed-off-by: Guido Günther Closes: #158 --- src/scanner.c | 3 ++ tests/data/example-client.h | 66 ++++++++++++++++++++++++++++++++++ tests/data/example-server.h | 66 ++++++++++++++++++++++++++++++++++ tests/data/small-client-core.h | 3 ++ tests/data/small-client.h | 3 ++ tests/data/small-server-core.h | 3 ++ tests/data/small-server.h | 3 ++ 7 files changed, 147 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index b470c916..36ac905f 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1636,6 +1636,8 @@ emit_header(struct protocol *protocol, enum side side) printf("\n"); wl_list_for_each(i, &protocol->interface_list, link) { + printf("#ifndef %s_INTERFACE\n", i->uppercase_name); + printf("#define %s_INTERFACE\n", i->uppercase_name); printf("/**\n" " * @page page_iface_%s %s\n", i->name, i->name); @@ -1656,6 +1658,7 @@ emit_header(struct protocol *protocol, enum side side) printf(" */\n"); printf("extern const struct wl_interface " "%s_interface;\n", i->name); + printf("#endif\n"); } printf("\n"); diff --git a/tests/data/example-client.h b/tests/data/example-client.h index c40e3611..d421af9d 100644 --- a/tests/data/example-client.h +++ b/tests/data/example-client.h @@ -88,6 +88,8 @@ struct wl_subsurface; struct wl_surface; struct wl_touch; +#ifndef WL_DISPLAY_INTERFACE +#define WL_DISPLAY_INTERFACE /** * @page page_iface_wl_display wl_display * @section page_iface_wl_display_desc Description @@ -104,6 +106,9 @@ struct wl_touch; * is used for internal Wayland protocol features. */ extern const struct wl_interface wl_display_interface; +#endif +#ifndef WL_REGISTRY_INTERFACE +#define WL_REGISTRY_INTERFACE /** * @page page_iface_wl_registry wl_registry * @section page_iface_wl_registry_desc Description @@ -156,6 +161,9 @@ extern const struct wl_interface wl_display_interface; * the object. */ extern const struct wl_interface wl_registry_interface; +#endif +#ifndef WL_CALLBACK_INTERFACE +#define WL_CALLBACK_INTERFACE /** * @page page_iface_wl_callback wl_callback * @section page_iface_wl_callback_desc Description @@ -172,6 +180,9 @@ extern const struct wl_interface wl_registry_interface; * the related request is done. */ extern const struct wl_interface wl_callback_interface; +#endif +#ifndef WL_COMPOSITOR_INTERFACE +#define WL_COMPOSITOR_INTERFACE /** * @page page_iface_wl_compositor wl_compositor * @section page_iface_wl_compositor_desc Description @@ -190,6 +201,9 @@ extern const struct wl_interface wl_callback_interface; * surfaces into one displayable output. */ extern const struct wl_interface wl_compositor_interface; +#endif +#ifndef WL_SHM_POOL_INTERFACE +#define WL_SHM_POOL_INTERFACE /** * @page page_iface_wl_shm_pool wl_shm_pool * @section page_iface_wl_shm_pool_desc Description @@ -216,6 +230,9 @@ extern const struct wl_interface wl_compositor_interface; * a surface or for many small buffers. */ extern const struct wl_interface wl_shm_pool_interface; +#endif +#ifndef WL_SHM_INTERFACE +#define WL_SHM_INTERFACE /** * @page page_iface_wl_shm wl_shm * @section page_iface_wl_shm_desc Description @@ -246,6 +263,9 @@ extern const struct wl_interface wl_shm_pool_interface; * that can be used for buffers. */ extern const struct wl_interface wl_shm_interface; +#endif +#ifndef WL_BUFFER_INTERFACE +#define WL_BUFFER_INTERFACE /** * @page page_iface_wl_buffer wl_buffer * @section page_iface_wl_buffer_desc Description @@ -268,6 +288,9 @@ extern const struct wl_interface wl_shm_interface; * updates the contents is defined by the buffer factory interface. */ extern const struct wl_interface wl_buffer_interface; +#endif +#ifndef WL_DATA_OFFER_INTERFACE +#define WL_DATA_OFFER_INTERFACE /** * @page page_iface_wl_data_offer wl_data_offer * @section page_iface_wl_data_offer_desc Description @@ -292,6 +315,9 @@ extern const struct wl_interface wl_buffer_interface; * data directly from the source client. */ extern const struct wl_interface wl_data_offer_interface; +#endif +#ifndef WL_DATA_SOURCE_INTERFACE +#define WL_DATA_SOURCE_INTERFACE /** * @page page_iface_wl_data_source wl_data_source * @section page_iface_wl_data_source_desc Description @@ -312,6 +338,9 @@ extern const struct wl_interface wl_data_offer_interface; * to requests to transfer the data. */ extern const struct wl_interface wl_data_source_interface; +#endif +#ifndef WL_DATA_DEVICE_INTERFACE +#define WL_DATA_DEVICE_INTERFACE /** * @page page_iface_wl_data_device wl_data_device * @section page_iface_wl_data_device_desc Description @@ -334,6 +363,9 @@ extern const struct wl_interface wl_data_source_interface; * mechanisms such as copy-and-paste and drag-and-drop. */ extern const struct wl_interface wl_data_device_interface; +#endif +#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE +#define WL_DATA_DEVICE_MANAGER_INTERFACE /** * @page page_iface_wl_data_device_manager wl_data_device_manager * @section page_iface_wl_data_device_manager_desc Description @@ -366,6 +398,9 @@ extern const struct wl_interface wl_data_device_interface; * wl_data_offer.accept and wl_data_offer.finish for details. */ extern const struct wl_interface wl_data_device_manager_interface; +#endif +#ifndef WL_SHELL_INTERFACE +#define WL_SHELL_INTERFACE /** * @page page_iface_wl_shell wl_shell * @section page_iface_wl_shell_desc Description @@ -388,6 +423,9 @@ extern const struct wl_interface wl_data_device_manager_interface; * a basic surface. */ extern const struct wl_interface wl_shell_interface; +#endif +#ifndef WL_SHELL_SURFACE_INTERFACE +#define WL_SHELL_SURFACE_INTERFACE /** * @page page_iface_wl_shell_surface wl_shell_surface * @section page_iface_wl_shell_surface_desc Description @@ -422,6 +460,9 @@ extern const struct wl_interface wl_shell_interface; * the wl_surface object. */ extern const struct wl_interface wl_shell_surface_interface; +#endif +#ifndef WL_SURFACE_INTERFACE +#define WL_SURFACE_INTERFACE /** * @page page_iface_wl_surface wl_surface * @section page_iface_wl_surface_desc Description @@ -512,6 +553,9 @@ extern const struct wl_interface wl_shell_surface_interface; * switching is not allowed). */ extern const struct wl_interface wl_surface_interface; +#endif +#ifndef WL_SEAT_INTERFACE +#define WL_SEAT_INTERFACE /** * @page page_iface_wl_seat wl_seat * @section page_iface_wl_seat_desc Description @@ -532,6 +576,9 @@ extern const struct wl_interface wl_surface_interface; * maintains a keyboard focus and a pointer focus. */ extern const struct wl_interface wl_seat_interface; +#endif +#ifndef WL_POINTER_INTERFACE +#define WL_POINTER_INTERFACE /** * @page page_iface_wl_pointer wl_pointer * @section page_iface_wl_pointer_desc Description @@ -560,6 +607,9 @@ extern const struct wl_interface wl_seat_interface; * and scrolling. */ extern const struct wl_interface wl_pointer_interface; +#endif +#ifndef WL_KEYBOARD_INTERFACE +#define WL_KEYBOARD_INTERFACE /** * @page page_iface_wl_keyboard wl_keyboard * @section page_iface_wl_keyboard_desc Description @@ -576,6 +626,9 @@ extern const struct wl_interface wl_pointer_interface; * associated with a seat. */ extern const struct wl_interface wl_keyboard_interface; +#endif +#ifndef WL_TOUCH_INTERFACE +#define WL_TOUCH_INTERFACE /** * @page page_iface_wl_touch wl_touch * @section page_iface_wl_touch_desc Description @@ -604,6 +657,9 @@ extern const struct wl_interface wl_keyboard_interface; * contact point can be identified by the ID of the sequence. */ extern const struct wl_interface wl_touch_interface; +#endif +#ifndef WL_OUTPUT_INTERFACE +#define WL_OUTPUT_INTERFACE /** * @page page_iface_wl_output wl_output * @section page_iface_wl_output_desc Description @@ -628,6 +684,9 @@ extern const struct wl_interface wl_touch_interface; * as global during start up, or when a monitor is hotplugged. */ extern const struct wl_interface wl_output_interface; +#endif +#ifndef WL_REGION_INTERFACE +#define WL_REGION_INTERFACE /** * @page page_iface_wl_region wl_region * @section page_iface_wl_region_desc Description @@ -648,6 +707,9 @@ extern const struct wl_interface wl_output_interface; * regions of a surface. */ extern const struct wl_interface wl_region_interface; +#endif +#ifndef WL_SUBCOMPOSITOR_INTERFACE +#define WL_SUBCOMPOSITOR_INTERFACE /** * @page page_iface_wl_subcompositor wl_subcompositor * @section page_iface_wl_subcompositor_desc Description @@ -698,6 +760,9 @@ extern const struct wl_interface wl_region_interface; * processing to dedicated overlay hardware when possible. */ extern const struct wl_interface wl_subcompositor_interface; +#endif +#ifndef WL_SUBSURFACE_INTERFACE +#define WL_SUBSURFACE_INTERFACE /** * @page page_iface_wl_subsurface wl_subsurface * @section page_iface_wl_subsurface_desc Description @@ -808,6 +873,7 @@ extern const struct wl_interface wl_subcompositor_interface; * unmapped. */ extern const struct wl_interface wl_subsurface_interface; +#endif #ifndef WL_DISPLAY_ERROR_ENUM #define WL_DISPLAY_ERROR_ENUM diff --git a/tests/data/example-server.h b/tests/data/example-server.h index adfc973c..3311c5d7 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -91,6 +91,8 @@ struct wl_subsurface; struct wl_surface; struct wl_touch; +#ifndef WL_DISPLAY_INTERFACE +#define WL_DISPLAY_INTERFACE /** * @page page_iface_wl_display wl_display * @section page_iface_wl_display_desc Description @@ -107,6 +109,9 @@ struct wl_touch; * is used for internal Wayland protocol features. */ extern const struct wl_interface wl_display_interface; +#endif +#ifndef WL_REGISTRY_INTERFACE +#define WL_REGISTRY_INTERFACE /** * @page page_iface_wl_registry wl_registry * @section page_iface_wl_registry_desc Description @@ -159,6 +164,9 @@ extern const struct wl_interface wl_display_interface; * the object. */ extern const struct wl_interface wl_registry_interface; +#endif +#ifndef WL_CALLBACK_INTERFACE +#define WL_CALLBACK_INTERFACE /** * @page page_iface_wl_callback wl_callback * @section page_iface_wl_callback_desc Description @@ -175,6 +183,9 @@ extern const struct wl_interface wl_registry_interface; * the related request is done. */ extern const struct wl_interface wl_callback_interface; +#endif +#ifndef WL_COMPOSITOR_INTERFACE +#define WL_COMPOSITOR_INTERFACE /** * @page page_iface_wl_compositor wl_compositor * @section page_iface_wl_compositor_desc Description @@ -193,6 +204,9 @@ extern const struct wl_interface wl_callback_interface; * surfaces into one displayable output. */ extern const struct wl_interface wl_compositor_interface; +#endif +#ifndef WL_SHM_POOL_INTERFACE +#define WL_SHM_POOL_INTERFACE /** * @page page_iface_wl_shm_pool wl_shm_pool * @section page_iface_wl_shm_pool_desc Description @@ -219,6 +233,9 @@ extern const struct wl_interface wl_compositor_interface; * a surface or for many small buffers. */ extern const struct wl_interface wl_shm_pool_interface; +#endif +#ifndef WL_SHM_INTERFACE +#define WL_SHM_INTERFACE /** * @page page_iface_wl_shm wl_shm * @section page_iface_wl_shm_desc Description @@ -249,6 +266,9 @@ extern const struct wl_interface wl_shm_pool_interface; * that can be used for buffers. */ extern const struct wl_interface wl_shm_interface; +#endif +#ifndef WL_BUFFER_INTERFACE +#define WL_BUFFER_INTERFACE /** * @page page_iface_wl_buffer wl_buffer * @section page_iface_wl_buffer_desc Description @@ -271,6 +291,9 @@ extern const struct wl_interface wl_shm_interface; * updates the contents is defined by the buffer factory interface. */ extern const struct wl_interface wl_buffer_interface; +#endif +#ifndef WL_DATA_OFFER_INTERFACE +#define WL_DATA_OFFER_INTERFACE /** * @page page_iface_wl_data_offer wl_data_offer * @section page_iface_wl_data_offer_desc Description @@ -295,6 +318,9 @@ extern const struct wl_interface wl_buffer_interface; * data directly from the source client. */ extern const struct wl_interface wl_data_offer_interface; +#endif +#ifndef WL_DATA_SOURCE_INTERFACE +#define WL_DATA_SOURCE_INTERFACE /** * @page page_iface_wl_data_source wl_data_source * @section page_iface_wl_data_source_desc Description @@ -315,6 +341,9 @@ extern const struct wl_interface wl_data_offer_interface; * to requests to transfer the data. */ extern const struct wl_interface wl_data_source_interface; +#endif +#ifndef WL_DATA_DEVICE_INTERFACE +#define WL_DATA_DEVICE_INTERFACE /** * @page page_iface_wl_data_device wl_data_device * @section page_iface_wl_data_device_desc Description @@ -337,6 +366,9 @@ extern const struct wl_interface wl_data_source_interface; * mechanisms such as copy-and-paste and drag-and-drop. */ extern const struct wl_interface wl_data_device_interface; +#endif +#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE +#define WL_DATA_DEVICE_MANAGER_INTERFACE /** * @page page_iface_wl_data_device_manager wl_data_device_manager * @section page_iface_wl_data_device_manager_desc Description @@ -369,6 +401,9 @@ extern const struct wl_interface wl_data_device_interface; * wl_data_offer.accept and wl_data_offer.finish for details. */ extern const struct wl_interface wl_data_device_manager_interface; +#endif +#ifndef WL_SHELL_INTERFACE +#define WL_SHELL_INTERFACE /** * @page page_iface_wl_shell wl_shell * @section page_iface_wl_shell_desc Description @@ -391,6 +426,9 @@ extern const struct wl_interface wl_data_device_manager_interface; * a basic surface. */ extern const struct wl_interface wl_shell_interface; +#endif +#ifndef WL_SHELL_SURFACE_INTERFACE +#define WL_SHELL_SURFACE_INTERFACE /** * @page page_iface_wl_shell_surface wl_shell_surface * @section page_iface_wl_shell_surface_desc Description @@ -425,6 +463,9 @@ extern const struct wl_interface wl_shell_interface; * the wl_surface object. */ extern const struct wl_interface wl_shell_surface_interface; +#endif +#ifndef WL_SURFACE_INTERFACE +#define WL_SURFACE_INTERFACE /** * @page page_iface_wl_surface wl_surface * @section page_iface_wl_surface_desc Description @@ -515,6 +556,9 @@ extern const struct wl_interface wl_shell_surface_interface; * switching is not allowed). */ extern const struct wl_interface wl_surface_interface; +#endif +#ifndef WL_SEAT_INTERFACE +#define WL_SEAT_INTERFACE /** * @page page_iface_wl_seat wl_seat * @section page_iface_wl_seat_desc Description @@ -535,6 +579,9 @@ extern const struct wl_interface wl_surface_interface; * maintains a keyboard focus and a pointer focus. */ extern const struct wl_interface wl_seat_interface; +#endif +#ifndef WL_POINTER_INTERFACE +#define WL_POINTER_INTERFACE /** * @page page_iface_wl_pointer wl_pointer * @section page_iface_wl_pointer_desc Description @@ -563,6 +610,9 @@ extern const struct wl_interface wl_seat_interface; * and scrolling. */ extern const struct wl_interface wl_pointer_interface; +#endif +#ifndef WL_KEYBOARD_INTERFACE +#define WL_KEYBOARD_INTERFACE /** * @page page_iface_wl_keyboard wl_keyboard * @section page_iface_wl_keyboard_desc Description @@ -579,6 +629,9 @@ extern const struct wl_interface wl_pointer_interface; * associated with a seat. */ extern const struct wl_interface wl_keyboard_interface; +#endif +#ifndef WL_TOUCH_INTERFACE +#define WL_TOUCH_INTERFACE /** * @page page_iface_wl_touch wl_touch * @section page_iface_wl_touch_desc Description @@ -607,6 +660,9 @@ extern const struct wl_interface wl_keyboard_interface; * contact point can be identified by the ID of the sequence. */ extern const struct wl_interface wl_touch_interface; +#endif +#ifndef WL_OUTPUT_INTERFACE +#define WL_OUTPUT_INTERFACE /** * @page page_iface_wl_output wl_output * @section page_iface_wl_output_desc Description @@ -631,6 +687,9 @@ extern const struct wl_interface wl_touch_interface; * as global during start up, or when a monitor is hotplugged. */ extern const struct wl_interface wl_output_interface; +#endif +#ifndef WL_REGION_INTERFACE +#define WL_REGION_INTERFACE /** * @page page_iface_wl_region wl_region * @section page_iface_wl_region_desc Description @@ -651,6 +710,9 @@ extern const struct wl_interface wl_output_interface; * regions of a surface. */ extern const struct wl_interface wl_region_interface; +#endif +#ifndef WL_SUBCOMPOSITOR_INTERFACE +#define WL_SUBCOMPOSITOR_INTERFACE /** * @page page_iface_wl_subcompositor wl_subcompositor * @section page_iface_wl_subcompositor_desc Description @@ -701,6 +763,9 @@ extern const struct wl_interface wl_region_interface; * processing to dedicated overlay hardware when possible. */ extern const struct wl_interface wl_subcompositor_interface; +#endif +#ifndef WL_SUBSURFACE_INTERFACE +#define WL_SUBSURFACE_INTERFACE /** * @page page_iface_wl_subsurface wl_subsurface * @section page_iface_wl_subsurface_desc Description @@ -811,6 +876,7 @@ extern const struct wl_interface wl_subcompositor_interface; * unmapped. */ extern const struct wl_interface wl_subsurface_interface; +#endif #ifndef WL_DISPLAY_ERROR_ENUM #define WL_DISPLAY_ERROR_ENUM diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h index c85cca60..d4247570 100644 --- a/tests/data/small-client-core.h +++ b/tests/data/small-client-core.h @@ -46,6 +46,8 @@ struct another_intf; struct intf_A; struct intf_not_here; +#ifndef INTF_A_INTERFACE +#define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description @@ -60,6 +62,7 @@ struct intf_not_here; * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; +#endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM diff --git a/tests/data/small-client.h b/tests/data/small-client.h index 884346d5..2a1f961d 100644 --- a/tests/data/small-client.h +++ b/tests/data/small-client.h @@ -46,6 +46,8 @@ struct another_intf; struct intf_A; struct intf_not_here; +#ifndef INTF_A_INTERFACE +#define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description @@ -60,6 +62,7 @@ struct intf_not_here; * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; +#endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h index 6dd2d05a..f0fd1f90 100644 --- a/tests/data/small-server-core.h +++ b/tests/data/small-server-core.h @@ -49,6 +49,8 @@ struct another_intf; struct intf_A; struct intf_not_here; +#ifndef INTF_A_INTERFACE +#define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description @@ -63,6 +65,7 @@ struct intf_not_here; * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; +#endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM diff --git a/tests/data/small-server.h b/tests/data/small-server.h index 4763f5bb..22b81133 100644 --- a/tests/data/small-server.h +++ b/tests/data/small-server.h @@ -49,6 +49,8 @@ struct another_intf; struct intf_A; struct intf_not_here; +#ifndef INTF_A_INTERFACE +#define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description @@ -63,6 +65,7 @@ struct intf_not_here; * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; +#endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM From df969706f4cd479a525a69a13f86589d6b313b5b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 16 Apr 2020 15:57:07 +1000 Subject: [PATCH 0662/1152] Replace initial 8 spaces with a tab for all xml files This is the style used in wayland.xml which is the only file we really care about for git blame information. So let's adjust all others to that style for consistency and fix editorconfig to avoid messing this up in the future. Signed-off-by: Peter Hutterer --- .editorconfig | 2 +- doc/publican/sources/Book_Info.xml | 6 ++--- doc/publican/sources/Compositors.xml | 4 ++-- doc/publican/sources/Foreword.xml | 4 ++-- doc/publican/sources/Introduction.xml | 12 +++++----- doc/publican/sources/Preface.xml | 2 +- doc/publican/sources/Xwayland.xml | 34 +++++++++++++-------------- protocol/tests.xml | 4 ++-- protocol/wayland.xml | 14 +++++------ tests/data/small.xml | 6 ++--- 10 files changed, 44 insertions(+), 44 deletions(-) diff --git a/.editorconfig b/.editorconfig index 803abf34..50b77409 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,7 +10,7 @@ indent_size = 8 max_line_length = 80 [*.xml] -indent_style = space +indent_style = tab indent_size = 2 tab_width = 8 diff --git a/doc/publican/sources/Book_Info.xml b/doc/publican/sources/Book_Info.xml index 0b7bf079..897673a0 100644 --- a/doc/publican/sources/Book_Info.xml +++ b/doc/publican/sources/Book_Info.xml @@ -28,9 +28,9 @@ - - Wayland logo - + + Wayland logo + diff --git a/doc/publican/sources/Compositors.xml b/doc/publican/sources/Compositors.xml index ad27f61e..7a7bdaa0 100644 --- a/doc/publican/sources/Compositors.xml +++ b/doc/publican/sources/Compositors.xml @@ -61,8 +61,8 @@ Possible examples for session compositors include - - + + gnome-shell diff --git a/doc/publican/sources/Foreword.xml b/doc/publican/sources/Foreword.xml index e6875a34..46fda2be 100644 --- a/doc/publican/sources/Foreword.xml +++ b/doc/publican/sources/Foreword.xml @@ -22,7 +22,7 @@ Yours, - the Wayland open-source community - November 2012 + the Wayland open-source community + November 2012 diff --git a/doc/publican/sources/Introduction.xml b/doc/publican/sources/Introduction.xml index 7516c33e..276db2da 100644 --- a/doc/publican/sources/Introduction.xml +++ b/doc/publican/sources/Introduction.xml @@ -33,9 +33,9 @@ - - X architecture diagram - + + X architecture diagram + @@ -96,9 +96,9 @@ - - Wayland architecture diagram - + + Wayland architecture diagram + diff --git a/doc/publican/sources/Preface.xml b/doc/publican/sources/Preface.xml index 61720a9c..17c6ebff 100644 --- a/doc/publican/sources/Preface.xml +++ b/doc/publican/sources/Preface.xml @@ -15,6 +15,6 @@ Best, - Kristian Høgsberg + Kristian Høgsberg diff --git a/doc/publican/sources/Xwayland.xml b/doc/publican/sources/Xwayland.xml index a39866f8..e4399910 100644 --- a/doc/publican/sources/Xwayland.xml +++ b/doc/publican/sources/Xwayland.xml @@ -78,11 +78,11 @@

Xwayland architecture diagram - - - - - + + + + +
@@ -150,20 +150,20 @@
Window identification - In Xwayland, an X11 window may have a corresponding wl_surface object - in Wayland. The wl_surface object is used for input and output: it is - referenced by input events and used to provide the X11 window content - to the Wayland compositor. The X11 window and the wl_surface live in - different protocol streams, and they need to be matched for XWM to do - its job. + In Xwayland, an X11 window may have a corresponding wl_surface object + in Wayland. The wl_surface object is used for input and output: it is + referenced by input events and used to provide the X11 window content + to the Wayland compositor. The X11 window and the wl_surface live in + different protocol streams, and they need to be matched for XWM to do + its job. - When Xwayland creates a wl_surface on Wayland, it will also send an X11 - ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying - the wl_surface Wayland object ID as the first 32-bit data element. This - is how XWM can associate a wl_surface with an X11 window. Note that - the request to create a wl_surface and the ID message may arrive in any - order in the Wayland compositor. + When Xwayland creates a wl_surface on Wayland, it will also send an X11 + ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying + the wl_surface Wayland object ID as the first 32-bit data element. This + is how XWM can associate a wl_surface with an X11 window. Note that + the request to create a wl_surface and the ID message may arrive in any + order in the Wayland compositor.
diff --git a/protocol/tests.xml b/protocol/tests.xml index ea56ae49..22d80a10 100644 --- a/protocol/tests.xml +++ b/protocol/tests.xml @@ -43,8 +43,8 @@ - Tells this fd passer object about another one to send events - to for more complicated fd leak tests. + Tells this fd passer object about another one to send events + to for more complicated fd leak tests. diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d3e54ee7..5dce5323 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -298,7 +298,7 @@ will be reported by the format event. + run the automated script that keeps it in sync with drm_fourcc.h. --> @@ -594,9 +594,9 @@ will be raised otherwise. + enum="wl_data_device_manager.dnd_action"/> + enum="wl_data_device_manager.dnd_action"/>
@@ -606,7 +606,7 @@ side changes its offered actions through wl_data_source.set_actions. + enum="wl_data_device_manager.dnd_action"/> @@ -648,7 +648,7 @@ must happen before the call to wl_data_offer.finish. + enum="wl_data_device_manager.dnd_action"/> @@ -746,7 +746,7 @@ for drag-and-drop will raise a protocol error. + enum="wl_data_device_manager.dnd_action"/>
@@ -803,7 +803,7 @@ they reflect the current action. + enum="wl_data_device_manager.dnd_action"/> diff --git a/tests/data/small.xml b/tests/data/small.xml index a6e62ad8..832ed0e1 100644 --- a/tests/data/small.xml +++ b/tests/data/small.xml @@ -50,9 +50,9 @@ - - - + + + From ef611a803ef7cd1bc7147bfdc453ca1ee380e095 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Mon, 30 Mar 2020 18:29:08 +0200 Subject: [PATCH 0663/1152] doc: fix and clarify pointer image behaviour Signed-off-by: Yann Dirson --- doc/publican/sources/Protocol.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 69edd2cd..a472f1d5 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -400,11 +400,12 @@ request is ignored. To the client this will look like it successfully set the pointer image.
+ + Setting the pointer image to NULL causes the cursor to be hidden. + The compositor will revert the pointer image back to a default image - when no surface has the pointer focus for that device. Clients can - revert the pointer image back to the default image by setting a NULL - image. + when no surface has the pointer focus for that device. What if the pointer moves from one window which has set a special @@ -412,7 +413,10 @@ the motion event? The new surface will be stuck with the special pointer image. We can't just revert the pointer image on leaving a surface, since if we immediately enter a surface that sets a different - image, the image will flicker. Broken app, I suppose. + image, the image will flicker. If a client does not set a pointer image + when the pointer enters a surface, the pointer stays with the image set + by the last surface that changed it, possibly even hidden. Such a client + is likely just broken.
From 94c036d72b0269b4c1e0e0776267ce375adb6870 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Jun 2020 15:40:08 +1000 Subject: [PATCH 0664/1152] editorconfig: add settings for the .gitlab-ci.yml file Different indentation and we don't want a fixed line length here, wrapping yaml is prone to introduce bugs. Signed-off-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- .editorconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.editorconfig b/.editorconfig index 50b77409..d92e5e96 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,3 +17,8 @@ tab_width = 8 [*.py] indent_style = space indent_size = 4 + +[*.yml] +indent_style = space +indent_size = 2 +max_line_length = off From cf20f2414048cd7d9ad43ffcdb8f494a6431a623 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 4 Jun 2020 15:40:49 +1000 Subject: [PATCH 0665/1152] gitlab CI: update to use the fdo ci templates Instead of building a new debian image every time we build the repo, let's build it once and re-use it. This way we're more likely to spot actual bugs vs issues with the distribution (or mirrors). This is the same approach mesa, gstreamer, libinput, etc. already use. The pipeline consists of two parts: container-build and distribution-image. Both use the FDO_DISTRIBUTION_... variables to do their thing, the former to build an image, the latter to use that image. The container-build step is a noop if an image with that tag already exists in the registry, the templates take care of all that. The .debian.buster section groups the variables needed to easily extend all jobs requiring buster. Not all variables are used by all jobs but meh. The grouping is slightly odd because some debian-specific variables are in the global variables and others in the .debian.buster section. This grouping will make things easier if we extend to build on other distributions - then we have all packages and tags in one place. Because buster doesn't have a recent-enough version of meson, we install that from pip. Fixes #79 Signed-off-by: Peter Hutterer Reviewed-by: Pekka Paalanen --- .gitlab-ci.yml | 55 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1037fee0..b2e174fe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,50 @@ -image: debian:buster +.templates_sha: &template_sha bd8010dd0123d3f0dda4ef691078566af2842613 # see https://docs.gitlab.com/ee/ci/yaml/#includefile + + +include: + # Debian container builder template + - project: 'freedesktop/ci-templates' + ref: *template_sha + file: '/templates/debian.yml' + stages: + - prep - build -before_script: - - echo 'path-exclude=/usr/share/doc/*' > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft - - echo 'path-exclude=/usr/share/man/*' >> /etc/dpkg/dpkg.cfg.d/99-exclude-cruft - - echo '#!/bin/sh' > /usr/sbin/policy-rc.d - - echo 'exit 101' >> /usr/sbin/policy-rc.d - - chmod +x /usr/sbin/policy-rc.d - - echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list - - apt-get update - - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson/buster-backports + +variables: + DEBIAN_PACKAGES: 'build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' + DEBIAN_EXEC: 'pip3 install meson==0.52.1' + # these tags should be updated each time the list of packages is updated + # changing these will force rebuilding the associated image + # Note: these tags have no meaning and are not tied to a particular + # wayland version + DEBIAN_TAG: '2020-06-05.1' + FDO_UPSTREAM_REPO: wayland/wayland + + +.debian.buster: + variables: + FDO_DISTRIBUTION_PACKAGES: $DEBIAN_PACKAGES + FDO_DISTRIBUTION_TAG: $DEBIAN_TAG + FDO_DISTRIBUTION_VERSION: 'buster' + FDO_DISTRIBUTION_EXEC: $DEBIAN_EXEC + + +debian:buster@container-prep: + extends: + - .debian.buster + - .fdo.container-build@debian + stage: prep + variables: + GIT_STRATEGY: none + build-native-autotools: + extends: + - .debian.buster + - .fdo.distribution-image@debian stage: build script: - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" @@ -36,7 +67,11 @@ build-native-autotools: - build-*/*.log - prefix-* + build-native-meson: + extends: + - .debian.buster + - .fdo.distribution-image@debian stage: build script: - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" From 21fad23a47ae3891fb92d6de4b82a00857e952c2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 May 2020 10:00:12 +0200 Subject: [PATCH 0666/1152] protocol: add seat missing_capability error The protocol says: > It is a protocol violation to issue this request on a seat that > has never had the pointer capability. But never defines an error code. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/165 --- protocol/wayland.xml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 5dce5323..12396911 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1743,6 +1743,14 @@ + + + These errors can be emitted in response to wl_seat requests. + + + + This is emitted whenever a seat gains or loses the pointer, @@ -1781,7 +1789,8 @@ This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has - never had the pointer capability. + never had the pointer capability. The missing_capability error will + be sent in this case. @@ -1794,7 +1803,8 @@ This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has - never had the keyboard capability. + never had the keyboard capability. The missing_capability error will + be sent in this case. @@ -1807,7 +1817,8 @@ This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has - never had the touch capability. + never had the touch capability. The missing_capability error will + be sent in this case. From 95a3272625296293c1d508e79a6e670b1af2abca Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 13 Nov 2019 20:39:01 +0100 Subject: [PATCH 0667/1152] cursor: Use spaces for alignment in the header Signed-off-by: Emmanuel Gil Peyrot --- cursor/wayland-cursor.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h index 40d3fc5c..01144c49 100644 --- a/cursor/wayland-cursor.h +++ b/cursor/wayland-cursor.h @@ -37,11 +37,11 @@ struct wl_buffer; struct wl_shm; struct wl_cursor_image { - uint32_t width; /* actual width */ - uint32_t height; /* actual height */ - uint32_t hotspot_x; /* hot spot x (must be inside image) */ - uint32_t hotspot_y; /* hot spot y (must be inside image) */ - uint32_t delay; /* animation delay to next frame (ms) */ + uint32_t width; /* actual width */ + uint32_t height; /* actual height */ + uint32_t hotspot_x; /* hot spot x (must be inside image) */ + uint32_t hotspot_y; /* hot spot y (must be inside image) */ + uint32_t delay; /* animation delay to next frame (ms) */ }; struct wl_cursor { From c81cbae3f2233f189d32927c6d33c90804f28953 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 13 Nov 2019 22:53:21 +0100 Subject: [PATCH 0668/1152] cursor: Properly document wl_cursor_image and wl_cursor Signed-off-by: Emmanuel Gil Peyrot --- cursor/wayland-cursor.h | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h index 01144c49..915a1100 100644 --- a/cursor/wayland-cursor.h +++ b/cursor/wayland-cursor.h @@ -36,17 +36,36 @@ struct wl_cursor_theme; struct wl_buffer; struct wl_shm; +/** A still image part of a cursor + * + * Use `wl_cursor_image_get_buffer()` to get the corresponding `struct + * wl_buffer` to attach to your `struct wl_surface`. */ struct wl_cursor_image { - uint32_t width; /* actual width */ - uint32_t height; /* actual height */ - uint32_t hotspot_x; /* hot spot x (must be inside image) */ - uint32_t hotspot_y; /* hot spot y (must be inside image) */ - uint32_t delay; /* animation delay to next frame (ms) */ + /** Actual width */ + uint32_t width; + + /** Actual height */ + uint32_t height; + + /** Hot spot x (must be inside image) */ + uint32_t hotspot_x; + + /** Hot spot y (must be inside image) */ + uint32_t hotspot_y; + + /** Animation delay to next frame (ms) */ + uint32_t delay; }; +/** A cursor, as returned by `wl_cursor_theme_get_cursor()` */ struct wl_cursor { + /** How many images there are in this cursor’s animation */ unsigned int image_count; + + /** The array of still images composing this animation */ struct wl_cursor_image **images; + + /** The name of this cursor */ char *name; }; From 3feed6e723154dcb045e589f161a76d4ff382c91 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 13 Nov 2019 22:53:49 +0100 Subject: [PATCH 0669/1152] doc: Document libwayland-cursor with autotools Signed-off-by: Emmanuel Gil Peyrot --- doc/doxygen/Makefile.am | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 31d953c0..86fd8bf7 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -3,8 +3,10 @@ noinst_DATA = \ xml/Client/index.xml \ + xml/Cursor/index.xml \ xml/Server/index.xml \ html/Client/index.html \ + html/Cursor/index.html \ html/Server/index.html dist_noinst_DATA = wayland.doxygen.in @@ -17,6 +19,10 @@ scanned_src_files_Client = \ $(top_srcdir)/src/wayland-client.h \ $(top_srcdir)/src/wayland-client-core.h +scanned_src_files_Cursor = \ + $(top_srcdir)/cursor/wayland-cursor.c \ + $(top_srcdir)/cursor/wayland-cursor.h + scanned_src_files_Server = \ $(scanned_src_files_shared) \ $(top_srcdir)/src/event-loop.c \ @@ -42,6 +48,9 @@ extra_doxygen_Client = \ $(top_builddir)/protocol/wayland-client-protocol.h \ $(extra_doxygen) +extra_doxygen_Cursor = \ + $(extra_doxygen) + diagramsdir := $(srcdir)/dot diagramssrc := $(wildcard $(diagramsdir)/*.gv) diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png)) @@ -53,7 +62,7 @@ diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map)) dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") # Listing various directories that might need to be created. -alldirsrel := xml xml/Client xml/Server man/man3 html/Client html/Server +alldirsrel := xml xml/Client xml/Server xml/Cursor man/man3 html/Client html/Server html/Cursor alldirs := $(patsubst %,$(CURDIR)/%,$(alldirsrel)) $(diagrams): $(diagramssrc) From a61ae8eca858f866636eb2721f42ca0fa7fd06f8 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 22 Jan 2020 13:26:47 +0100 Subject: [PATCH 0670/1152] doc: Document libwayland-cursor with meson Signed-off-by: Emmanuel Gil Peyrot --- doc/doxygen/mainpage.dox | 1 + doc/doxygen/meson.build | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox index ca1da53c..352f69be 100644 --- a/doc/doxygen/mainpage.dox +++ b/doc/doxygen/mainpage.dox @@ -6,6 +6,7 @@ * * - Server-side API * - Client-side API + * - Cursor helper library API * * Further documentation about the architecture and principles of Wayland is * available in the diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build index c39b2826..f2bee147 100644 --- a/doc/doxygen/meson.build +++ b/doc/doxygen/meson.build @@ -38,6 +38,11 @@ server_files = files([ '../../src/wayland-shm.c', ]) +cursor_files = files([ + '../../cursor/wayland-cursor.c', + '../../cursor/wayland-cursor.h', +]) + extra_client_files = [ 'mainpage.dox', wayland_client_protocol_h, @@ -48,6 +53,10 @@ extra_server_files = [ wayland_server_protocol_h, ] +extra_cursor_files = [ + 'mainpage.dox', +] + gen_doxygen = find_program('gen-doxygen.py') subdir('xml') @@ -56,6 +65,7 @@ formats = { 'html': { 'Client': shared_files + client_files + extra_client_files, 'Server': shared_files + server_files + extra_server_files, + 'Cursor': shared_files + cursor_files + extra_cursor_files, }, } @@ -86,7 +96,7 @@ foreach f_name, sections: formats endforeach endforeach -man_files = shared_files + server_files + client_files +man_files = shared_files + server_files + client_files + cursor_files custom_target( 'man-pages-3', command: [ From 4aa6eb868a8646b99c5b552a48aa31043530a269 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sun, 24 May 2020 02:28:31 +0300 Subject: [PATCH 0671/1152] Clarify the order of wl_keyboard.modifiers Consider that we set the modifier for the modifier key as well, and that you have the option to change your layout when both shifts pressed. This realized by making the shift keys produce 'Group_switch' when you press the shift key and the shift modifier is already active. So sending modifier before the key event will result in 'Group_switch' each time you press shift. That being said, the order of modifiers should be updated after the key/enter event, so it'll only affect future keypresses, not the current one. See: https://lists.x.org/archives/xorg-devel/2014-July/043110.html Signed-off-by: Kirill Chibisov --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 12396911..8e4a75c6 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2202,6 +2202,9 @@ Notification that this seat's keyboard focus is on a certain surface. + + The compositor must send the wl_keyboard.modifiers event after this + event. @@ -2233,6 +2236,9 @@ A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. + + If this event produces a change in modifiers, then the resulting + wl_keyboard.modifiers event must be sent after this event. From 57b7c7d9463f391a1cae6fa049b2f98a3de3d09e Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sun, 24 May 2020 14:12:44 +0300 Subject: [PATCH 0672/1152] Clarify clients behavior on wl_keyboard.leave Clients must assume that every key, including modifiers, are lifted after getting wl_keyboard.leave event, not doing so could lead to key repeat keep going after the user changes focus, or stuck modifiers, when the user interacts with client without keyboard focus. Signed-off-by: Kirill Chibisov --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8e4a75c6..97846807 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2218,6 +2218,9 @@ The leave notification is sent before the enter notification for the new focus. + + After this event client must assume that all keys, including modifiers, + are lifted and also it must stop key repeating if there's some going on. From 1dfd2169dad8c7a39506b52afbedd42b7a1d9dbe Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 3 Feb 2020 15:45:58 +0100 Subject: [PATCH 0673/1152] protocol: disambiguate key codes in wl_keyboard.key Explain that wl_keyboard.key yields platform-specific key codes. Some compositors use Linux key codes (defined in the linux/input-event-codes.h header file, e.g. KEY_ESC), however clients should not assume that this is always the case. The only reliable way for clients to interpret key codes is to feed them into a keyboard mapping. Signed-off-by: Simon Ser --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 97846807..d087e25e 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2240,6 +2240,9 @@ The time argument is a timestamp with millisecond granularity, with an undefined base. + The key is a platform-specific key code that can be interpreted + by feeding it to the keyboard mapping (see the keymap event). + If this event produces a change in modifiers, then the resulting wl_keyboard.modifiers event must be sent after this event. From 4e16ef0aed8db425afc8910b2a9708b57e165d39 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Fri, 14 Aug 2020 10:24:02 +1000 Subject: [PATCH 0674/1152] protocol: Minor gramatical fix. Signed-off-by: Christopher James Halse Rogers --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d087e25e..09e4f4c6 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2732,7 +2732,7 @@ wl_surface state directly. A sub-surface is initially in the synchronized mode. - Sub-surfaces have also other kind of state, which is managed by + Sub-surfaces also have another kind of state, which is managed by wl_subsurface requests, as opposed to wl_surface requests. This state includes the sub-surface position relative to the parent surface (wl_subsurface.set_position), and the stacking order of From 9b7171f955225c5481c493c34e5ebe639cfd67ef Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 9 Jul 2020 14:44:04 +1000 Subject: [PATCH 0675/1152] Add a basic gitlab issue template This makes the Bug template available in the new issues form. Ideally a majority of users will select this template and then realize that they're in the wrong repo. Making this a default is a feature of the enterprise gitlab version only, see https://docs.gitlab.com/ce/user/project/description_templates.html#overview Signed-off-by: Peter Hutterer --- .gitlab/issue_templates/Bug.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitlab/issue_templates/Bug.md diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 00000000..b78a6153 --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,8 @@ + From fc3beac71f631fb16ee2257e9a6c9ec07cd0c90d Mon Sep 17 00:00:00 2001 From: Valentin Date: Fri, 4 Sep 2020 12:12:56 +0200 Subject: [PATCH 0676/1152] Use fixed size integer type This type is meant to be 4 bytes large as seen in _XcursorReadUInt which always reads 4 bytes. An unsigned int is often 4 bytes large but this isnt' guaranteed so it is cleaner to use the exact type we want. Signed-off-by: Valentin Kettner --- cursor/xcursor.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cursor/xcursor.h b/cursor/xcursor.h index 62e23220..c1ca12c1 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -26,8 +26,10 @@ #ifndef XCURSOR_H #define XCURSOR_H +#include + typedef int XcursorBool; -typedef unsigned int XcursorUInt; +typedef uint32_t XcursorUInt; typedef XcursorUInt XcursorDim; typedef XcursorUInt XcursorPixel; From 1ab6a81816f52c17be2138ba569256b5afc029f2 Mon Sep 17 00:00:00 2001 From: Valentin Date: Fri, 4 Sep 2020 12:15:03 +0200 Subject: [PATCH 0677/1152] Fix undefined behavior Without the casts the bytes accesses get converted to int. but int is not guaranteed to be 4 bytes large. Even when it is 4 bytes large `bytes[3] << 24` does not fit because int is signed. Signed-off-by: Valentin Kettner --- cursor/xcursor.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 689c7026..1f1360fb 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -285,10 +285,11 @@ _XcursorReadUInt (XcursorFile *file, XcursorUInt *u) if ((*file->read) (file, bytes, 4) != 4) return XcursorFalse; - *u = ((bytes[0] << 0) | - (bytes[1] << 8) | - (bytes[2] << 16) | - (bytes[3] << 24)); + + *u = ((XcursorUInt)(bytes[0]) << 0) | + ((XcursorUInt)(bytes[1]) << 8) | + ((XcursorUInt)(bytes[2]) << 16) | + ((XcursorUInt)(bytes[3]) << 24); return XcursorTrue; } From 53dd99793dd95fcfc187a0ee81ab289dfbe7fc2a Mon Sep 17 00:00:00 2001 From: Nick Diego Yamane Date: Wed, 8 Jul 2020 10:48:19 -0400 Subject: [PATCH 0678/1152] protocol: Clarify how clients can cancel a drag operation Explicitly say that destroying a wl_data_source previously used in a wl_data_device::start_drag request will cancel the DND session. This is currently the only way to do it from client side (besides those "indirect" ones already documented) and all compositors work like that but it is not clear spec-wise it is the expected behaviour. Signed-off-by: Nick Diego Yamane --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 09e4f4c6..3475a791 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -829,7 +829,8 @@ for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing - internally. + internally. If source is destroyed, the drag-and-drop session will be + cancelled. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the From e53e0edf0f892670f3e8c5dd527b3bb22335d32d Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Thu, 29 Oct 2020 12:06:36 +0000 Subject: [PATCH 0679/1152] doc: make reproducible This setting makes Docbook section IDs consistent, and should allow Wayland builds that include documentation to be fully reproducible. Signed-off-by: Alyssa Ross --- doc/publican/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 898ca4fc..60305f49 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -9,6 +9,7 @@ custom_target( '--skip-validation', '--stringparam', 'chunk.section.depth=0', '--stringparam', 'toc.section.depth=1', + '--stringparam', 'generate.consistent.ids=1', '--stringparam', 'html.stylesheet=css/default.css', '-o', '@OUTPUT@', 'html', From 1ea08d748cfa86d7395315ca3e52085b0e1c8155 Mon Sep 17 00:00:00 2001 From: ganjing Date: Mon, 27 Jul 2020 11:22:40 +0800 Subject: [PATCH 0680/1152] cursor/convert_font.c: malloc cannot guarantee that the memory allocated is always successful --- cursor/convert_font.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cursor/convert_font.c b/cursor/convert_font.c index 45b6ac6b..74e45fbc 100644 --- a/cursor/convert_font.c +++ b/cursor/convert_font.c @@ -499,6 +499,11 @@ output_interesting_cursors() struct reconstructed_glyph *glyphs = malloc(n * sizeof(*glyphs)); + if (!glyphs) { + printf("reconstructed_glyph malloc failed\n"); + abort(); + } + for (i = 0; i < n; ++i) { struct glyph *cursor, *mask; find_cursor_and_mask(interesting_cursors[i].source_name, From d42b39ccab5baff33eb6a0d38d6d46ef0c442e89 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 15 Jul 2020 09:39:25 +0200 Subject: [PATCH 0681/1152] protocol: make it clear wl_surface.enter/leave are not for frame throttling Some clients rely on wl_surface.enter/leave to start/stop their rendering loop. There are cases where this doesn't work: - Some compositors don't send wl_surface.leave when a toplevel is hidden. For instance Sway doesn't send this event when a toplevel is on an inactive workspace (but doesn't send wl_surface.frame events). - Some compositors might still want applications to continue to render even if away from outputs. For instance a compositor that allows to screen record individual toplevels might not send a wl_surface.enter event for hidden toplevels. Signed-off-by: Simon Ser --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3475a791..f8968189 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1609,6 +1609,12 @@ This is emitted whenever a surface's creation, movement, or resizing results in it no longer having any part of it within the scanout region of an output. + + Clients should not use the number of outputs the surface is on for frame + throttling purposes. The surface might be hidden even if no leave event + has been sent, and the compositor might expect new surface content + updates even if no enter event has been sent. The frame event should be + used instead. From 6741dafbf7a50e8a3f3b7667b4fecbf7c55f21ff Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Apr 2020 19:08:53 +0200 Subject: [PATCH 0682/1152] protocol: deprecate non-current wl_output.mode The current wl_output.mode event has several issues when used to advertise modes that aren't current: - It's not possible to remove some modes. This is an issue for virtual outputs and when the kernel prunes some modes because of link limitations. - wl_output.mode fails to carry metadata such as aspect ratio, which results in duplicated or missing modes. - It's not clear, given the current set of protocols, how non-current modes are useful to clients. Xwayland ignores non-current modes. GNOME and wlroots already only advertise the current mode because of these issues. If a protocol needs the clients to know about all available modes, it should advertise these modes itself instead of relying on wl_output.mode. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/92 --- protocol/wayland.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f8968189..dce579db 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2547,6 +2547,10 @@ current. In other words, the current mode is always the last mode that was received with the current flag set. + Non-current modes are deprecated. A compositor can decide to only + advertise the current mode and never send other modes. Clients + should not rely on non-current modes. + The size of a mode is given in physical hardware units of the output device. This is not necessarily the same as the output size in the global compositor space. For instance, From 0f5cc8b71b787a3f567b0153f8b848af74e60aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Thu, 17 Dec 2020 15:39:46 -0500 Subject: [PATCH 0683/1152] doc: fix typos --- doc/publican/protocol-to-docbook.xsl | 2 +- doc/publican/sources/Protocol.xml | 6 +++--- doc/publican/sources/Server.xml | 2 +- doc/publican/sources/Xwayland.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl index 210e0dbb..79c938bb 100644 --- a/doc/publican/protocol-to-docbook.xsl +++ b/doc/publican/protocol-to-docbook.xsl @@ -146,7 +146,7 @@ - + diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index a472f1d5..97e9ba29 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -169,7 +169,7 @@ The 32-bit object ID. Generally, the interface used for the new object is inferred from the xml, but in the case where it's not - specified, a new_id is preceeded by a string specifying + specified, a new_id is preceded by a string specifying the interface name, and a uint specifying the version. @@ -214,7 +214,7 @@ The object creation hierarchy must be a tree. Otherwise, - infering object versions from the parent object becomes a much + inferring object versions from the parent object becomes a much more difficult to properly track. @@ -293,7 +293,7 @@ creating the object (either client or server). IDs allocated by the client are in the range [1, 0xfeffffff] while IDs allocated by the server are in the range [0xff000000, 0xffffffff]. The 0 ID is - reserved to represent a null or non-existant object. + reserved to represent a null or non-existent object. For efficiency purposes, the IDs are densely packed in the sense that the ID N will not be used until N-1 has been used. Any ID allocation diff --git a/doc/publican/sources/Server.xml b/doc/publican/sources/Server.xml index f627d64b..2333b1a4 100644 --- a/doc/publican/sources/Server.xml +++ b/doc/publican/sources/Server.xml @@ -24,7 +24,7 @@ Each open socket to a client is represented by a wl_client. The equvalent + linkend="Server-structwl__client">wl_client. The equivalent of the wl_proxy that libwayland-client uses to represent an object is wl_resource for diff --git a/doc/publican/sources/Xwayland.xml b/doc/publican/sources/Xwayland.xml index e4399910..79155598 100644 --- a/doc/publican/sources/Xwayland.xml +++ b/doc/publican/sources/Xwayland.xml @@ -145,7 +145,7 @@ Xwayland. It is often nearly impossible to prove that synchronous or blocking X11 calls from XWM cannot cause a deadlock, and therefore it is strongly recommended to make all X11 communications asynchronous. All - Wayland communications are already asynchonous by design. + Wayland communications are already asynchronous by design.
Window identification From efa5e3c8c6cd7559e1e9df397d8536a143615cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Thu, 17 Dec 2020 15:40:04 -0500 Subject: [PATCH 0684/1152] tests: fix typos --- tests/connection-test.c | 2 +- tests/newsignal-test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/connection-test.c b/tests/connection-test.c index a06a3cca..c04845bb 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -553,7 +553,7 @@ expected_fail_demarshal(struct marshal_data *data, const char *format, assert(errno == expected_error); } -/* These tests are verifying that the demarshaling code will gracefuly handle +/* These tests are verifying that the demarshaling code will gracefully handle * clients lying about string and array lengths and giving values near * UINT32_MAX. Before fixes f7fdface and f5b9e3b9 this test would crash on * 32bit systems. diff --git a/tests/newsignal-test.c b/tests/newsignal-test.c index f3a7bd98..051e10e8 100644 --- a/tests/newsignal-test.c +++ b/tests/newsignal-test.c @@ -223,7 +223,7 @@ TEST(signal_readd_listener) { /* Readding a listener is supported, that is it doesn't trigger an * infinite loop or other weird things, but if in a listener you - * readd another listener, that will not be fired in the current + * re-add another listener, that will not be fired in the current * signal emission. */ test_set_timeout(4); From b52e71c8ec1659aaefd970f1f284ece39d04ef05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Thu, 17 Dec 2020 15:40:38 -0500 Subject: [PATCH 0685/1152] CONTRIBUTING: fix typo "excercising" --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dcc9f56f..1ea351f0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -232,7 +232,7 @@ During review, the following matters should be checked: - Stable ABI or API additions must be justified by actual use cases, not only by speculation. They must also be documented, and it is strongly recommended to -include tests excercising the additions in the test suite. +include tests exercising the additions in the test suite. - The code fits the existing software architecture, e.g. no layering violations. From 0f0951d5c4d62fa5d1f2ccb5e69354b5116220a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Thu, 17 Dec 2020 15:40:58 -0500 Subject: [PATCH 0686/1152] cursor: fix typo "insufficent" --- cursor/os-compatibility.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 9eac2297..8d51e528 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -101,7 +101,7 @@ create_tmpfile_cloexec(char *tmpname) * * If the C library implements posix_fallocate(), it is used to * guarantee that disk space is available for the file at the - * given size. If disk space is insufficent, errno is set to ENOSPC. + * given size. If disk space is insufficient, errno is set to ENOSPC. * If posix_fallocate() is not supported, program may receive * SIGBUS on accessing mmap()'ed file contents instead. * From 4c086a8ce2b31f3d627a1bee778bf272d9ec9191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Thu, 17 Dec 2020 15:41:13 -0500 Subject: [PATCH 0687/1152] egl: fix typo "Backards" --- egl/wayland-egl-abi-check.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/egl/wayland-egl-abi-check.c b/egl/wayland-egl-abi-check.c index faa6b572..ea877d0e 100644 --- a/egl/wayland-egl-abi-check.c +++ b/egl/wayland-egl-abi-check.c @@ -112,7 +112,7 @@ struct wl_egl_window_v3 { do { \ if (offsetof(struct wl_egl_window ## a_ver, a_member) != \ offsetof(struct wl_egl_window ## b_ver, b_member)) { \ - printf("Backards incompatible change detected!\n " \ + printf("Backwards incompatible change detected!\n " \ "offsetof(struct wl_egl_window" #a_ver "::" #a_member ") != " \ "offsetof(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \ return 1; \ @@ -120,7 +120,7 @@ struct wl_egl_window_v3 { \ if (MEMBER_SIZE(struct wl_egl_window ## a_ver, a_member) != \ MEMBER_SIZE(struct wl_egl_window ## b_ver, b_member)) { \ - printf("Backards incompatible change detected!\n " \ + printf("Backwards incompatible change detected!\n " \ "MEMBER_SIZE(struct wl_egl_window" #a_ver "::" #a_member ") != " \ "MEMBER_SIZE(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \ return 1; \ @@ -134,7 +134,7 @@ struct wl_egl_window_v3 { do { \ if (sizeof(struct wl_egl_window ## a_ver) > \ sizeof(struct wl_egl_window ## b_ver)) { \ - printf("Backards incompatible change detected!\n " \ + printf("Backwards incompatible change detected!\n " \ "sizeof(struct wl_egl_window" #a_ver ") > " \ "sizeof(struct wl_egl_window" #b_ver ")\n"); \ return 1; \ @@ -145,7 +145,7 @@ struct wl_egl_window_v3 { do { \ if (sizeof(struct wl_egl_window ## a_ver) != \ sizeof(struct wl_egl_window)) { \ - printf("Backards incompatible change detected!\n " \ + printf("Backwards incompatible change detected!\n " \ "sizeof(struct wl_egl_window" #a_ver ") != " \ "sizeof(struct wl_egl_window)\n"); \ return 1; \ @@ -156,7 +156,7 @@ struct wl_egl_window_v3 { do { \ if ((WL_EGL_WINDOW_VERSION ## a_ver) >= \ (WL_EGL_WINDOW_VERSION ## b_ver)) { \ - printf("Backards incompatible change detected!\n " \ + printf("Backwards incompatible change detected!\n " \ "WL_EGL_WINDOW_VERSION" #a_ver " >= " \ "WL_EGL_WINDOW_VERSION" #b_ver "\n"); \ return 1; \ @@ -167,7 +167,7 @@ struct wl_egl_window_v3 { do { \ if ((WL_EGL_WINDOW_VERSION ## a_ver) != \ (WL_EGL_WINDOW_VERSION)) { \ - printf("Backards incompatible change detected!\n " \ + printf("Backwards incompatible change detected!\n " \ "WL_EGL_WINDOW_VERSION" #a_ver " != " \ "WL_EGL_WINDOW_VERSION\n"); \ return 1; \ From dad8575a4bf3fabf1f480dfd0b8272935ed41bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Thu, 17 Dec 2020 15:42:10 -0500 Subject: [PATCH 0688/1152] server: fix typos --- src/wayland-server-core.h | 4 ++-- src/wayland-server.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index fd4fc3ee..64d71696 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -261,8 +261,8 @@ wl_global_destroy(struct wl_global *global); * A filter function enables the server to decide which globals to * advertise to each client. * - * When a wl_global filter is set, the given callback funtion will be - * called during wl_global advertisment and binding. + * When a wl_global filter is set, the given callback function will be + * called during wl_global advertisement and binding. * * This function should return true if the global object should be made * visible to the client or false otherwise. diff --git a/src/wayland-server.c b/src/wayland-server.c index 3f48dfe4..d8ccb220 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -689,12 +689,12 @@ wl_resource_post_no_memory(struct wl_resource *resource) * Before Wayland 1.2.0, the definition of struct wl_resource was public. * It was made opaque just before 1.2.0, and later new fields were added. * The new fields cannot be accessed if a program is using the deprecated - * defition, as there would not be memory allocated for them. + * definition, as there would not be memory allocated for them. * * The creation pattern for the deprecated definition was wl_resource_init() * followed by wl_client_add_resource(). wl_resource_init() was an inline * function and no longer exists, but binaries might still carry it. - * wl_client_add_resource() still exists for ABI compatiblity. + * wl_client_add_resource() still exists for ABI compatibility. */ static bool resource_is_deprecated(struct wl_resource *resource) @@ -891,7 +891,7 @@ wl_client_destroy(struct wl_client *client) /* Check if a global filter is registered and use it if any. * - * If no wl_global filter has been registered, this funtion will + * If no wl_global filter has been registered, this function will * return true, allowing the wl_global to be visible to the wl_client */ static bool @@ -1151,13 +1151,13 @@ wl_display_destroy(struct wl_display *display) /** Set a filter function for global objects * * \param display The Wayland display object. - * \param filter The global filter funtion. + * \param filter The global filter function. * \param data User data to be associated with the global filter. * \return None. * * Set a filter for the wl_display to advertise or hide global objects * to clients. - * The set filter will be used during wl_global advertisment to + * The set filter will be used during wl_global advertisement to * determine whether a global object should be advertised to a * given client, and during wl_global binding to determine whether * a given client should be allowed to bind to a global. @@ -2035,7 +2035,7 @@ wl_client_for_each_resource(struct wl_client *client, * without corrupting the signal's list. * * Before passing a wl_priv_signal object to any other function it must be - * initialized by useing wl_priv_signal_init(). + * initialized by using wl_priv_signal_init(). * * \memberof wl_priv_signal */ @@ -2065,7 +2065,7 @@ wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener) * * Returns the listener added to the given \a signal and with the given * \a notify function, or NULL if there isn't any. - * Calling this function from withing wl_priv_signal_emit() is safe and will + * Calling this function from within wl_priv_signal_emit() is safe and will * return the correct value. * * \memberof wl_priv_signal From ea09c2fde7fcfc7e24a19ae5c5977981e9befeb7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 21 Dec 2020 11:16:05 +0100 Subject: [PATCH 0689/1152] build: bump to version 1.18.91 for the alpha release --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index ace83b2e..8c5a4ec8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [18]) -m4_define([wayland_micro_version], [90]) +m4_define([wayland_micro_version], [91]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index b67b101b..8d7b4a97 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.18.90', + version: '1.18.91', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From 74182eb605bf0e45b777cb8b942f5263877c7e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Yhuel?= Date: Thu, 2 Apr 2020 18:25:54 +0200 Subject: [PATCH 0690/1152] meson: link with -lrt if needed for clock_gettime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is already done in autotools, and fixes the build with glibc < 2.17. Signed-off-by: Loïc Yhuel --- meson.build | 8 ++++++++ src/meson.build | 5 +++-- tests/meson.build | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 8d7b4a97..fb0d01d6 100644 --- a/meson.build +++ b/meson.build @@ -56,6 +56,14 @@ if get_option('libraries') error('@0@ is needed to compile Wayland libraries'.format(d['symbol'])) endif endforeach + + rt_dep = [] + if not cc.has_function('clock_gettime', prefix: '#include ') + rt_dep = cc.find_library('rt') + if not cc.has_function('clock_gettime', prefix: '#include ', dependencies: rt_dep) + error('clock_gettime not found') + endif + endif endif scanner_deps = [ dependency('expat') ] diff --git a/src/meson.build b/src/meson.build index 2d1485c6..d91c503e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -77,7 +77,7 @@ if get_option('libraries') 'connection.c', 'wayland-os.c' ], - dependencies: [ ffi_dep, ] + dependencies: [ ffi_dep, rt_dep ] ) wayland_private_dep = declare_dependency( @@ -155,7 +155,8 @@ if get_option('libraries') wayland_private_dep, wayland_util_dep, mathlib_dep, - threads_dep + threads_dep, + rt_dep ], include_directories: root_inc, install: true diff --git a/tests/meson.build b/tests/meson.build index 224f48dd..a32ac508 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -54,7 +54,7 @@ benchmark( executable( 'fixed-benchmark', 'fixed-benchmark.c', - dependencies: test_runner_dep + dependencies: [ test_runner_dep, rt_dep ] ) ) From d01dee9784292027581726d51654834ed31d6931 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 14 Dec 2020 17:27:45 +0100 Subject: [PATCH 0691/1152] Remove TODO These TODO items are outdated (either done or not applicable anymore). Let's migrate items that we want to keep to GitLab issues. Signed-off-by: Simon Ser --- TODO | 146 ----------------------------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 TODO diff --git a/TODO b/TODO deleted file mode 100644 index 88fa5cc9..00000000 --- a/TODO +++ /dev/null @@ -1,146 +0,0 @@ -Core wayland protocol - - - Maybe try to make remote wayland actually happen, to see if there - is something in the protocol/architecture that makes it harder than - it should be. - -ICCCM - - - mime-type guidelines for data_source (ie, both dnd and selection): - recommended types for text or images, types that a clipboard - manager must support, mime-types must be listed in preferred order - - - we need a "no kb focus please" mechanism. Or should this be - implicit in a specific surface type? - -EWMH - - - configure should provide dx_left, dx_right, dy_top, dy_bottom, or - dx, dy, width and height. - - - move to workspace, keep on top, on all workspaces, minimize etc - requests for implementing client side window menu? or just make a - "show window menu" request to let the compositor display and manage - a popup window? - - - window move and resize functionality for kb and touch. - - - Protocol for specifying title bar rectangle (for moving - unresponsive apps). Rectangle for close button, so we can popup - force-close dialog if application doesn't respond to ping event - when user clicks there. We could use the region mechanism here - too. - - - popup placement protocol logic. - - - subsurface mechanism. we need this for cases where we would use an - X subwindow for gl or video other different visual type. - -EGL/gbm - - - Land Robert Braggs EGL extensions: frame age, swap with damage - - - Make it possible to share buffers from compositor to clients. - Tricky part here is how to indicate to EGL on the server side that - it should make an EGLImage available to a client. We'll need a - "create a wl_buffer for this EGLImage for this client" kind of - entry point. - - - Protocol for arbitrating access to scanout buffers (physically - contiguous memory). When a client goes fullscreen (or ideally as - the compositor starts the animation that will make it fullscreen) - we send a "give up your scanout buffer" to the current fullscreen - client (if any) and when the client acks that we send a "try to - allocate a scanout buffer now" event to the fullscreen-to-be - client. - - -Misc - - - glyph cache - - - Needs a mechanism to pass buffers to client. - - buffer = drm.create_buffer(); /* buffer with stuff in it */ - - cache.upload(buffer, x, y, width, height, int hash) - - drm.buffer: id, name, stride etc /* event to announce cache buffer */ - - cache.image: hash, buffer, x, y, stride /* event to announce - * location in cache */ - - cache.reject: hash /* no upload for you! */ - - cache.retire: buffer /* cache has stopped using buffer, please - * reupload whatever you had in that buffer */ - - - A "please suspend" event from the compositor, to indicate to an - application that it's no longer visible/active. Or maybe discard - buffer, as in "wayland discarded your buffer, it's no longer - visible, you can stop updating it now.", reattach, as in "oh hey, - I'm about to show your buffer that I threw away, what was it - again?". for wayland system compositor vt switcing, for example, - to be able to throw away the surfaces in the session we're - switching away from. for minimized windows that we don't want live - thumb nails for. etc. - - -Clients and ports - - - port gtk+ - - - draw window decorations in gtkwindow.c - - - Details about pointer grabs. wayland doesn't have active grabs, - menus will behave subtly different. Under X, clicking a menu - open grabs the pointer and clicking outside the window pops down - the menu and swallows the click. without active grabs we can't - swallow the click. I'm sure there much more... - - - dnd, copy-paste - - - Investigate DirectFB on Wayland (or is that Wayland on DirectFB?) - - -Ideas - - - A wayland settings protocol to tell clients about themes (icons, - cursors, widget themes), fonts details (family, hinting - preferences) etc. Just send all settings at connect time, send - updates when a setting change. Getting a little close to gconf - here, but could be pretty simple: - - interface "settings": - event int_value(string name, int value) - event string_value(string name, string value) - - but maybe it's better to just require that clients get that from - somewhere else (gconf/dbus). - - -Crazy ideas - - - AF_WAYLAND - A new socket type. Eliminate compositor context - switch by making kernel understand enough of wayland that it can - forward input events as wayland events and do page flipping in - response to surface_attach requests: - - - ioctl(wayland_fd, "surface_attach to object 5 should do a kms page - flip on ctrc 2"); - - - what about multiple crtcs? what about frame event for other - clients? - - - forward these input devices to the client - - - "scancode 124 pressed or released with scan codes 18,22 and 30 - held down gives control back to userspace wayland. - - - what about maintaining cursor position? what about pointer - acceleration? maybe this only works in "client cursor mode", - where wayland hides the cursor and only sends relative events? - Solves the composited cursor problem. How does X show its - cursor then? - - - Probably not worth it. From 69b8eaf3852839079e18a57c3b86fa71ddf72354 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 6 Jan 2021 20:18:58 +0100 Subject: [PATCH 0692/1152] build: bump to version 1.18.92 for the beta release --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8c5a4ec8..8ac10d5b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [18]) -m4_define([wayland_micro_version], [91]) +m4_define([wayland_micro_version], [92]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index fb0d01d6..5a4ad639 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.18.91', + version: '1.18.92', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From d32e77692ce7faada2a44c9a8ee2e2fc1bc7461d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Yhuel?= Date: Thu, 14 Nov 2019 14:13:17 +0100 Subject: [PATCH 0693/1152] server: Allow absolute paths in WAYLAND_DISPLAY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compositor should handle absolute paths in WAYLAND_DISPLAY like the clients, ie not adding the XDG_RUNTIME_DIR prefix if it's an absolute path. This allows to create the wayland socket in a separate directory for system compositors if desired. Clients could then directly inherit the environment variable. Signed-off-by: Loïc Yhuel --- src/wayland-server.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index d8ccb220..d83bdecd 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1481,28 +1481,32 @@ static int wl_socket_init_for_display_name(struct wl_socket *s, const char *name) { int name_size; - const char *runtime_dir; + const char *runtime_dir = ""; + const char *separator = ""; - runtime_dir = getenv("XDG_RUNTIME_DIR"); - if (!runtime_dir) { - wl_log("error: XDG_RUNTIME_DIR not set in the environment\n"); + if (name[0] != '/') { + runtime_dir = getenv("XDG_RUNTIME_DIR"); + if (!runtime_dir) { + wl_log("error: XDG_RUNTIME_DIR not set in the environment\n"); - /* to prevent programs reporting - * "failed to add socket: Success" */ - errno = ENOENT; - return -1; + /* to prevent programs reporting + * "failed to add socket: Success" */ + errno = ENOENT; + return -1; + } + separator = "/"; } s->addr.sun_family = AF_LOCAL; name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path, - "%s/%s", runtime_dir, name) + 1; + "%s%s%s", runtime_dir, separator, name) + 1; s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name); assert(name_size > 0); if (name_size > (int)sizeof s->addr.sun_path) { - wl_log("error: socket path \"%s/%s\" plus null terminator" - " exceeds 108 bytes\n", runtime_dir, name); + wl_log("error: socket path \"%s%s%s\" plus null terminator" + " exceeds 108 bytes\n", runtime_dir, separator, name); *s->addr.sun_path = 0; /* to prevent programs reporting * "failed to add socket: Success" */ @@ -1641,14 +1645,17 @@ wl_display_add_socket_fd(struct wl_display *display, int sock_fd) * variable for the socket name. If WAYLAND_DISPLAY is not set, then default * wayland-0 is used. * - * The Unix socket will be created in the directory pointed to by environment - * variable XDG_RUNTIME_DIR. If XDG_RUNTIME_DIR is not set, then this function - * fails and returns -1. + * If the socket name is a relative path, the Unix socket will be created in + * the directory pointed to by environment variable XDG_RUNTIME_DIR. If + * XDG_RUNTIME_DIR is not set, then this function fails and returns -1. * - * The length of socket path, i.e., the path set in XDG_RUNTIME_DIR and the - * socket name, must not exceed the maximum length of a Unix socket path. - * The function also fails if the user do not have write permission in the - * XDG_RUNTIME_DIR path or if the socket name is already in use. + * If the socket name is an absolute path, then it is used as-is for the + * the Unix socket. + * + * The length of the computed socket path must not exceed the maximum length + * of a Unix socket path. + * The function also fails if the user does not have write permission in the + * directory or if the path is already in use. * * \memberof wl_display */ From db8b64ca5e6f92eb2377aa1c182f38db8fbc351f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Jan 2021 11:51:39 +0100 Subject: [PATCH 0694/1152] protocol: sync wl_shm.format with libdrm 2.4.104 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds 4 new formats. Signed-off-by: Simon Ser Reviewed-by: Jonas Ådahl Acked-by: Daniel Stone --- protocol/wayland.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index dce579db..471daf66 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -399,6 +399,10 @@ + + + + From 0344e08ce01e963f113b31d0d976e5120cc3e75d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 20 Jan 2021 22:35:34 +0100 Subject: [PATCH 0695/1152] build: bump to 1.18.93 for the RC1 release --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8ac10d5b..2fd18418 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [18]) -m4_define([wayland_micro_version], [92]) +m4_define([wayland_micro_version], [93]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index 5a4ad639..2fddacb7 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.18.92', + version: '1.18.93', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From e60398b1755bfcdf09f040d3769131fe0d9762fc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 27 Jan 2021 17:48:01 +0100 Subject: [PATCH 0696/1152] build: bump to version 1.19.0 for the official release --- configure.ac | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 2fd18418..7f2f393d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [18]) -m4_define([wayland_micro_version], [93]) +m4_define([wayland_minor_version], [19]) +m4_define([wayland_micro_version], [0]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index 2fddacb7..11c35fa6 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.18.93', + version: '1.19.0', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From f1cc5d0c375e41c73969ec72ca86d8421a9cb1e6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 27 Jan 2021 18:45:57 +0100 Subject: [PATCH 0697/1152] build: re-open master for regular development --- configure.ac | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7f2f393d..748ac474 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.64]) m4_define([wayland_major_version], [1]) m4_define([wayland_minor_version], [19]) -m4_define([wayland_micro_version], [0]) +m4_define([wayland_micro_version], [90]) m4_define([wayland_version], [wayland_major_version.wayland_minor_version.wayland_micro_version]) diff --git a/meson.build b/meson.build index 11c35fa6..dd5774a8 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', 'cpp', - version: '1.19.0', + version: '1.19.90', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From efab39642ec9f446b98b2fb7c194306a033099a4 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 11 Jun 2020 13:39:56 -0600 Subject: [PATCH 0698/1152] protocol: Add type attribute to events This allows specifying events to be destructors, which is useful for non-C language bindings. It is unused in wayland-scanner. Signed-off-by: Tadeo Kondrak --- protocol/wayland.dtd | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd index 15f20ab6..ee062eea 100644 --- a/protocol/wayland.dtd +++ b/protocol/wayland.dtd @@ -10,6 +10,7 @@ + From ddf21afa6ee99ad6a00705cc74b62a1c4907776b Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 11 Jun 2020 13:41:09 -0600 Subject: [PATCH 0699/1152] protocol: Specify wl_callback::done to be a destructor event It's the only destructor event in the core protocol, and destructor events were previously unannotated. Signed-off-by: Tadeo Kondrak --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 471daf66..61e0366d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -179,7 +179,7 @@ the related request is done. - + Notify the client when the related request is done. From 70f1c83fd9380bf40d904b2806c2af07e688e960 Mon Sep 17 00:00:00 2001 From: sheepwall Date: Mon, 22 Feb 2021 18:19:13 +0100 Subject: [PATCH 0700/1152] server: remove duplicate include Signed-off-by: August Svensson --- src/wayland-server.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index d83bdecd..0ce5daf6 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include From 727c7903b27870bed0063814dd594466f21bf6eb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 25 Feb 2021 23:49:00 +0100 Subject: [PATCH 0701/1152] client: assert queue display matches proxy In wl_proxy_set_queue, passing a wl_event_queue from a completely unrelated wl_display could lead to object IDs mismatches. Add an assertion to catch this case. It's always a user bug if this happens. Signed-off-by: Simon Ser --- src/wayland-client.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 21d46067..58531eb0 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2177,10 +2177,12 @@ wl_proxy_get_class(struct wl_proxy *proxy) WL_EXPORT void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) { - if (queue) + if (queue) { + assert(proxy->display == queue->display); proxy->queue = queue; - else + } else { proxy->queue = &proxy->display->default_queue; + } } /** Create a proxy wrapper for making queue assignments thread-safe From 2b22160fb690a76247aa9bd0be3069ff43e8239f Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 24 Feb 2021 16:02:54 +0200 Subject: [PATCH 0702/1152] server: add wl_display getter for wl_global This can be useful if the compositor wants to call wl_global_destroy() with some delay but it doesn't have the wl_display object associated with the global, which is needed to get access to the event loop. Signed-off-by: Vlad Zahorodnii --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 64d71696..cbc70c09 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -279,6 +279,9 @@ wl_display_set_global_filter(struct wl_display *display, const struct wl_interface * wl_global_get_interface(const struct wl_global *global); +struct wl_display * +wl_global_get_display(const struct wl_global *global); + void * wl_global_get_user_data(const struct wl_global *global); diff --git a/src/wayland-server.c b/src/wayland-server.c index 0ce5daf6..0120326e 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1277,6 +1277,20 @@ wl_global_get_interface(const struct wl_global *global) return global->interface; } +/** Get the display object for the given global + * + * \param global The global object + * \return The display object the global is associated with. + * + * \memberof wl_global + * \since 1.20 + */ +WL_EXPORT struct wl_display * +wl_global_get_display(const struct wl_global *global) +{ + return global->display; +} + WL_EXPORT void * wl_global_get_user_data(const struct wl_global *global) { From 3bda3d1b4729c8ee7c533520a199611cb841bc8f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 14 Dec 2020 14:46:46 +0100 Subject: [PATCH 0703/1152] build: drop autotools Meson now replaces autotools. Signed-off-by: Simon Ser --- .gitignore | 40 --- .gitlab-ci.yml | 33 +-- Makefile.am | 341 ------------------------ autogen.sh | 9 - configure.ac | 202 -------------- cursor/wayland-cursor-uninstalled.pc.in | 8 - cursor/wayland-cursor.pc.in | 10 - doc/Makefile.am | 1 - doc/doxygen/Makefile.am | 113 -------- doc/publican/Makefile.am | 169 ------------ egl/wayland-egl-backend.h | 4 +- egl/wayland-egl-backend.pc.in | 9 - egl/wayland-egl.pc.in | 11 - m4/.gitignore | 5 - m4/weston.m4 | 37 --- releasing.txt | 10 +- src/wayland-client-uninstalled.pc.in | 9 - src/wayland-client.pc.in | 12 - src/wayland-scanner-uninstalled.pc.in | 6 - src/wayland-scanner.pc.in | 9 - src/wayland-server-uninstalled.pc.in | 9 - src/wayland-server.pc.in | 12 - 22 files changed, 10 insertions(+), 1049 deletions(-) delete mode 100644 Makefile.am delete mode 100755 autogen.sh delete mode 100644 configure.ac delete mode 100644 cursor/wayland-cursor-uninstalled.pc.in delete mode 100644 cursor/wayland-cursor.pc.in delete mode 100644 doc/Makefile.am delete mode 100644 doc/doxygen/Makefile.am delete mode 100644 doc/publican/Makefile.am delete mode 100644 egl/wayland-egl-backend.pc.in delete mode 100644 egl/wayland-egl.pc.in delete mode 100644 m4/.gitignore delete mode 100644 m4/weston.m4 delete mode 100644 src/wayland-client-uninstalled.pc.in delete mode 100644 src/wayland-client.pc.in delete mode 100644 src/wayland-scanner-uninstalled.pc.in delete mode 100644 src/wayland-scanner.pc.in delete mode 100644 src/wayland-server-uninstalled.pc.in delete mode 100644 src/wayland-server.pc.in diff --git a/.gitignore b/.gitignore index eadea12e..4fefe5d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,48 +1,8 @@ *.announce -*.deps -*.jpg -*.la -*.lo -*.o -*.pc *.sig -*.so *.swp -*.3 -*.7 *.log -*.trs *.tar.xz *~ -*-test -.libs -.dirstamp cscope.out ctags -/aclocal.m4 -/wayland-scanner.m4 -/autom4te.cache -/compile -/config.guess -/config.h -/config.h.in -/config.log -/config.mk -/config.status -/config.sub -/configure -/depcomp -/install-sh -/libtool -/ltmain.sh -/missing -/stamp-h1 -/test-driver -/tests/output/ -Makefile -Makefile.in -exec-fd-leak-checker -fixed-benchmark -/wayland-egl-abi-check -/wayland-scanner -protocol/*.[ch] diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b2e174fe..d2b07437 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,13 +14,13 @@ stages: variables: - DEBIAN_PACKAGES: 'build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' + DEBIAN_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' DEBIAN_EXEC: 'pip3 install meson==0.52.1' # these tags should be updated each time the list of packages is updated # changing these will force rebuilding the associated image # Note: these tags have no meaning and are not tied to a particular # wayland version - DEBIAN_TAG: '2020-06-05.1' + DEBIAN_TAG: '2020-12-14.0' FDO_UPSTREAM_REPO: wayland/wayland @@ -41,34 +41,7 @@ debian:buster@container-prep: GIT_STRATEGY: none -build-native-autotools: - extends: - - .debian.buster - - .fdo.distribution-image@debian - stage: build - script: - - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" - - export PREFIX="$(pwd)/prefix-$BUILD_ID" - - export BUILDDIR="$(pwd)/build-$BUILD_ID" - - export MAKEFLAGS="-j4" - - mkdir "$BUILDDIR" "$PREFIX" - - cd "$BUILDDIR" - - ../autogen.sh --prefix="$PREFIX" --with-icondir=/usr/share/X11/icons - - make all - - make check - - make install - - make distcheck - artifacts: - name: wayland-$CI_COMMIT_SHA-$CI_JOB_ID - when: always - paths: - - build-*/wayland-*.tar.xz - - build-*/wayland*/_build/sub/*.log - - build-*/*.log - - prefix-* - - -build-native-meson: +build-native: extends: - .debian.buster - .fdo.distribution-image@debian diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index b9438b7e..00000000 --- a/Makefile.am +++ /dev/null @@ -1,341 +0,0 @@ -if BUILD_DOCS -SUBDIRS = doc -endif - -ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} - -AM_CPPFLAGS = \ - -I$(top_builddir)/src \ - -I$(top_srcdir)/src \ - -I$(top_builddir)/protocol - -AM_CFLAGS = $(GCC_CFLAGS) - -aclocaldir = $(datadir)/aclocal -dist_aclocal_DATA = wayland-scanner.m4 - -dist_pkgdata_DATA = \ - wayland-scanner.mk \ - protocol/wayland.xml \ - protocol/wayland.dtd - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = - -bin_PROGRAMS = wayland-scanner -wayland_scanner_SOURCES = src/scanner.c -wayland_scanner_CPPFLAGS = $(AM_CPPFLAGS) -include config.h -wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(LIBXML_CFLAGS) $(AM_CFLAGS) -wayland_scanner_LDADD = $(EXPAT_LIBS) $(LIBXML_LIBS) libwayland-util.la -pkgconfig_DATA += src/wayland-scanner.pc - -if DTD_VALIDATION -wayland_scanner_SOURCES += src/dtddata.S -endif -src/dtddata.o: protocol/wayland.dtd - -if USE_HOST_SCANNER -wayland_scanner = wayland-scanner -else -$(BUILT_SOURCES) : wayland-scanner -wayland_scanner = $(top_builddir)/wayland-scanner -endif - -libwayland_util_la_CFLAGS = $(AM_CFLAGS) -libwayland_util_la_SOURCES = \ - src/wayland-util.c \ - src/wayland-util.h - -noinst_LTLIBRARIES = libwayland-util.la - -if ENABLE_LIBRARIES -noinst_LTLIBRARIES += libwayland-private.la -lib_LTLIBRARIES = libwayland-server.la libwayland-client.la - -libwayland_private_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -libwayland_private_la_SOURCES = \ - src/connection.c \ - src/wayland-os.c \ - src/wayland-os.h \ - src/wayland-private.h \ - src/wayland-server-private.h - -include_HEADERS = \ - src/wayland-util.h \ - src/wayland-server.h \ - src/wayland-server-core.h \ - src/wayland-client.h \ - src/wayland-client-core.h \ - src/wayland-version.h - -nodist_include_HEADERS = \ - protocol/wayland-server-protocol.h \ - protocol/wayland-client-protocol.h - -libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread -libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm -libwayland_server_la_LDFLAGS = -version-info 1:0:1 -libwayland_server_la_SOURCES = \ - src/wayland-server.c \ - src/wayland-shm.c \ - src/event-loop.c - -nodist_libwayland_server_la_SOURCES = \ - protocol/wayland-server-protocol.h \ - protocol/wayland-protocol.c - -libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread -libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm -libwayland_client_la_LDFLAGS = -version-info 3:0:3 -libwayland_client_la_SOURCES = \ - src/wayland-client.c - -nodist_libwayland_client_la_SOURCES = \ - protocol/wayland-client-protocol.h \ - protocol/wayland-protocol.c - -pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc - -protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml -if USE_HOST_SCANNER - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s code $< $@ -else - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s public-code $< $@ -endif - -protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header $< $@ - -protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header $< $@ - -protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header -c < $< > $@ - -protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header -c < $< > $@ - -BUILT_SOURCES = \ - $(nodist_libwayland_server_la_SOURCES) \ - $(nodist_libwayland_client_la_SOURCES) \ - $(nodist_headers_test_SOURCES) \ - $(nodist_display_test_SOURCES) - -CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db -DISTCLEANFILES = src/wayland-version.h -EXTRA_DIST = CONTRIBUTING.md - - - -lib_LTLIBRARIES += libwayland-cursor.la - -include_HEADERS += cursor/wayland-cursor.h - -libwayland_cursor_la_SOURCES = \ - cursor/wayland-cursor.c \ - cursor/os-compatibility.c \ - cursor/os-compatibility.h \ - cursor/cursor-data.h \ - cursor/xcursor.c \ - cursor/xcursor.h -libwayland_cursor_la_LIBADD = libwayland-client.la - -pkgconfig_DATA += cursor/wayland-cursor.pc - -libwayland_cursor_la_CFLAGS = \ - $(AM_CFLAGS) \ - -I$(top_builddir)/src \ - -I$(top_srcdir)/src \ - -DICONDIR=\"$(ICONDIR)\" - -lib_LTLIBRARIES += libwayland-egl.la - -include_HEADERS += egl/wayland-egl.h -include_HEADERS += egl/wayland-egl-core.h - -libwayland_egl_la_SOURCES = egl/wayland-egl.c -libwayland_egl_la_LDFLAGS = -version-info 1 - -pkgconfig_DATA += egl/wayland-egl.pc - -## XXX: backend interface -include_HEADERS += egl/wayland-egl-backend.h -pkgconfig_DATA += egl/wayland-egl-backend.pc - -built_test_programs = \ - array-test \ - client-test \ - display-test \ - connection-test \ - event-loop-test \ - fixed-test \ - interface-test \ - list-test \ - map-test \ - os-wrappers-test \ - sanity-test \ - socket-test \ - queue-test \ - proxy-test \ - signal-test \ - newsignal-test \ - resources-test \ - message-test \ - headers-test \ - compositor-introspection-test \ - protocol-logger-test \ - wayland-egl-abi-check - -EXTRA_DIST += egl/wayland-egl-symbols-check - -check_PROGRAMS = wayland-egl-abi-check -wayland_egl_abi_check_SOURCES = egl/wayland-egl-abi-check.c - -if ENABLE_CPP_TEST -built_test_programs += cpp-compile-test -endif - -AM_TESTS_ENVIRONMENT = \ - export WAYLAND_SCANNER='$(top_builddir)/wayland-scanner' \ - TEST_DATA_DIR='$(top_srcdir)/tests/data' \ - TEST_OUTPUT_DIR='$(top_builddir)/tests/output' \ - WAYLAND_EGL_LIB='$(top_builddir)/.libs/libwayland-egl.so' \ - SED=$(SED) \ - NM='$(NM)' \ - ; - -TESTS = $(built_test_programs) \ - egl/wayland-egl-symbols-check \ - tests/scanner-test.sh - -noinst_PROGRAMS = \ - $(built_test_programs) \ - exec-fd-leak-checker \ - fixed-benchmark - -noinst_LTLIBRARIES += \ - libtest-runner.la \ - libtest-helpers.la - -libtest_helpers_la_SOURCES = tests/test-helpers.c - -libtest_runner_la_SOURCES = \ - tests/test-runner.c \ - tests/test-runner.h \ - tests/test-compositor.h \ - tests/test-compositor.c -libtest_runner_la_LIBADD = \ - libwayland-private.la \ - libwayland-util.la \ - libwayland-client.la \ - libwayland-server.la \ - libtest-helpers.la \ - $(RT_LIBS) $(DL_LIBS) $(FFI_LIBS) - -array_test_SOURCES = tests/array-test.c -array_test_LDADD = libtest-runner.la -client_test_SOURCES = tests/client-test.c -client_test_LDADD = libtest-runner.la -display_test_CFLAGS = -pthread -display_test_SOURCES = tests/display-test.c -display_test_LDADD = libtest-runner.la -nodist_display_test_SOURCES = \ - protocol/tests-server-protocol.h \ - protocol/tests-client-protocol.h \ - protocol/tests-protocol.c -connection_test_SOURCES = tests/connection-test.c -connection_test_LDADD = libtest-runner.la -event_loop_test_SOURCES = tests/event-loop-test.c -event_loop_test_LDADD = libtest-runner.la -fixed_test_SOURCES = tests/fixed-test.c -fixed_test_LDADD = libtest-runner.la -interface_test_SOURCES = tests/interface-test.c -interface_test_LDADD = libtest-runner.la -list_test_SOURCES = tests/list-test.c -list_test_LDADD = libtest-runner.la -map_test_SOURCES = tests/map-test.c -map_test_LDADD = libtest-runner.la -sanity_test_SOURCES = tests/sanity-test.c -sanity_test_LDADD = libtest-runner.la -socket_test_SOURCES = tests/socket-test.c -socket_test_LDADD = libtest-runner.la -queue_test_SOURCES = tests/queue-test.c -queue_test_LDADD = libtest-runner.la -proxy_test_SOURCES = tests/proxy-test.c -proxy_test_LDADD = libtest-runner.la -signal_test_SOURCES = tests/signal-test.c -signal_test_LDADD = libtest-runner.la -# wayland-server.c is needed here to access wl_priv_* functions -newsignal_test_SOURCES = tests/newsignal-test.c src/wayland-server.c -newsignal_test_LDADD = libtest-runner.la -resources_test_SOURCES = tests/resources-test.c -resources_test_LDADD = libtest-runner.la -message_test_SOURCES = tests/message-test.c -message_test_LDADD = libtest-runner.la -compositor_introspection_test_SOURCES = tests/compositor-introspection-test.c -compositor_introspection_test_LDADD = libtest-runner.la -protocol_logger_test_SOURCES = tests/protocol-logger-test.c -protocol_logger_test_LDADD = libtest-runner.la -headers_test_SOURCES = tests/headers-test.c \ - tests/headers-protocol-test.c \ - tests/headers-protocol-core-test.c -nodist_headers_test_SOURCES = \ - protocol/wayland-server-protocol-core.h \ - protocol/wayland-client-protocol-core.h - -if ENABLE_CPP_TEST -cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp -endif - -fixed_benchmark_SOURCES = tests/fixed-benchmark.c -fixed_benchmark_LDADD = $(RT_LIBS) - -os_wrappers_test_SOURCES = tests/os-wrappers-test.c -os_wrappers_test_LDADD = libtest-runner.la - -exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c -exec_fd_leak_checker_LDADD = libtest-helpers.la - -EXTRA_DIST += tests/scanner-test.sh \ - protocol/tests.xml \ - tests/data/bad-identifier-arg.xml \ - tests/data/bad-identifier-entry.xml \ - tests/data/bad-identifier-enum.xml \ - tests/data/bad-identifier-event.xml \ - tests/data/bad-identifier-interface.xml \ - tests/data/bad-identifier-protocol.xml \ - tests/data/bad-identifier-request.xml \ - tests/data/example.xml \ - tests/data/example-client.h \ - tests/data/example-server.h \ - tests/data/example-code.c \ - tests/data/small.xml \ - tests/data/small-code.c \ - tests/data/small-client.h \ - tests/data/small-server.h \ - tests/data/small-code-core.c \ - tests/data/small-client-core.h \ - tests/data/small-server-core.h \ - tests/data/small-private-code.c \ - meson.build \ - meson_options.txt \ - cursor/meson.build \ - doc/meson.build \ - doc/doxygen/mainpage.dox \ - doc/doxygen/meson.build \ - doc/doxygen/gen-doxygen.py \ - doc/doxygen/xml/meson.build \ - doc/doxygen/xml/Client/meson.build \ - doc/doxygen/xml/Server/meson.build \ - doc/publican/meson.build \ - doc/publican/sources/meson.build \ - egl/meson.build \ - src/meson.build \ - tests/meson.build - -tests/scanner-test.sh: $(top_builddir)/wayland-scanner - -clean-local: - -rm -rf tests/output - -endif #ENABLE_LIBRARIES diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 916169a4..00000000 --- a/autogen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. -( - cd "$srcdir" && - autoreconf --force -v --install -) || exit -test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 748ac474..00000000 --- a/configure.ac +++ /dev/null @@ -1,202 +0,0 @@ -AC_PREREQ([2.64]) - -m4_define([wayland_major_version], [1]) -m4_define([wayland_minor_version], [19]) -m4_define([wayland_micro_version], [90]) -m4_define([wayland_version], - [wayland_major_version.wayland_minor_version.wayland_micro_version]) - -AC_INIT([wayland], - [wayland_version], - [https://gitlab.freedesktop.org/wayland/wayland/issues/], - [wayland], - [https://wayland.freedesktop.org/]) - -AC_SUBST([WAYLAND_VERSION_MAJOR], [wayland_major_version]) -AC_SUBST([WAYLAND_VERSION_MINOR], [wayland_minor_version]) -AC_SUBST([WAYLAND_VERSION_MICRO], [wayland_micro_version]) -AC_SUBST([WAYLAND_VERSION], [wayland_version]) - -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_MACRO_DIR([m4]) - -AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects]) - -AM_SILENT_RULES([yes]) - -# Check for programs -AC_PROG_CC -AC_PROG_CXX -AC_PROG_GREP -AM_PROG_AS -AC_PROG_NM - -# check if we have C++ compiler. This is hacky workaround, -# for a reason why it is this way see -# http://lists.gnu.org/archive/html/bug-autoconf/2010-05/msg00001.html -have_cpp_compiler=yes - -if ! which "$CXX" &>/dev/null; then - have_cpp_compiler=no -fi - -AM_CONDITIONAL(ENABLE_CPP_TEST, test "x$have_cpp_compiler" = "xyes") - -# Initialize libtool -LT_PREREQ([2.2]) -LT_INIT([disable-static]) - -PKG_PROG_PKG_CONFIG() - -AC_ARG_ENABLE([fatal-warnings], - AC_HELP_STRING([--enable-fatal-warnings], - [Build with -Werror]), - [enable_fatal_warnings=$enableval], - [enable_fatal_warnings=no]) -AS_IF([test x"$enable_fatal_warnings" != "xno"], [ - WERROR_CFLAGS="-Werror" -]) - -if test "x$GCC" = "xyes"; then - GCC_CFLAGS="$WERROR_CFLAGS -Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden" -fi -AC_SUBST(GCC_CFLAGS) - -AC_CHECK_HEADERS([sys/prctl.h]) -AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl memfd_create strndup]) - -# *BSD don't have libdl, but they have its functions in libc -WESTON_SEARCH_LIBS([DL], [dl], [dlsym]) - -# OpenBSD doesn't have librt, but it has its functions in libc -WESTON_SEARCH_LIBS([RT], [rt], [clock_gettime]) - -AC_ARG_ENABLE([libraries], - [AC_HELP_STRING([--disable-libraries], - [Disable compilation of wayland libraries])], - [], - [enable_libraries=yes]) - -AC_ARG_WITH([host-scanner], - [AC_HELP_STRING([--with-host-scanner], - [Use installed wayland-scanner from host PATH during build])], - [], - [with_host_scanner=no]) - -AC_ARG_ENABLE([documentation], - [AC_HELP_STRING([--disable-documentation], - [Disable building the documentation])], - [], - [enable_documentation=yes]) - -AC_ARG_ENABLE([dtd-validation], - [AC_HELP_STRING([--disable-dtd-validation], - [Disable DTD validation of the protocol])], - [], - [enable_dtd_validation=yes]) - -AM_CONDITIONAL(USE_HOST_SCANNER, test "x$with_host_scanner" = xyes) - -AM_CONDITIONAL(ENABLE_LIBRARIES, test "x$enable_libraries" = xyes) - -AC_ARG_WITH(icondir, [ --with-icondir= Look for cursor icons here], - [ ICONDIR=$withval], - [ ICONDIR=${datadir}/icons]) -AC_SUBST([ICONDIR]) - -if test "x$enable_libraries" = "xyes"; then - PKG_CHECK_MODULES(FFI, [libffi]) - AC_CHECK_DECL(SFD_CLOEXEC,[], - [AC_MSG_ERROR("SFD_CLOEXEC is needed to compile wayland libraries")], - [[#include ]]) - AC_CHECK_DECL(TFD_CLOEXEC,[], - [AC_MSG_ERROR("TFD_CLOEXEC is needed to compile wayland libraries")], - [[#include ]]) - AC_CHECK_DECL(CLOCK_MONOTONIC,[], - [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland libraries")], - [[#include ]]) -fi - -PKG_CHECK_MODULES(EXPAT, [expat]) - -AM_CONDITIONAL([DTD_VALIDATION], [test "x$enable_dtd_validation" = "xyes"]) -if test "x$enable_dtd_validation" = "xyes"; then - PKG_CHECK_MODULES(LIBXML, [libxml-2.0]) - AC_DEFINE(HAVE_LIBXML, 1, [libxml-2.0 is available]) - AC_CONFIG_LINKS([src/wayland.dtd.embed:protocol/wayland.dtd]) -fi - -AC_PATH_PROG(XSLTPROC, xsltproc) -AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"]) - - -AM_CONDITIONAL(BUILD_DOCS, [test x$enable_documentation = xyes]) -if test "x$enable_documentation" = "xyes"; then - AC_PATH_PROG(DOXYGEN, doxygen) - - if test "x$DOXYGEN" = "x"; then - AC_MSG_ERROR([Documentation build requested but doxygen not found. Install doxygen or disable the documentation using --disable-documentation]) - fi - - AC_MSG_CHECKING([for compatible doxygen version]) - doxygen_version=`$DOXYGEN --version` - AS_VERSION_COMPARE([$doxygen_version], [1.6.0], - [AC_MSG_RESULT([no]) - AC_MSG_ERROR([Doxygen $doxygen_version too old. Doxygen 1.6+ required for documentation build. Install required doxygen version or disable the documentation using --disable-documentation])], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([yes])]) - - AC_PATH_PROG(XMLTO, xmlto) - - if test "x$XMLTO" = "x"; then - AC_MSG_ERROR([Documentation build requested but xmlto not found. Install xmlto or disable the documentation using --disable-documentation]) - fi - - AC_PATH_PROG(DOT, dot) - if test "x$DOT" = "x"; then - AC_MSG_ERROR([Documentation build requested but graphviz's dot not found. Install graphviz or disable the documentation using --disable-documentation]) - fi - AC_MSG_CHECKING([for compatible dot version]) - dot_version=`$DOT -V 2>&1|$GREP -o ['[0-9]*\.[0-9]*\.[0-9]*']` - AS_VERSION_COMPARE([$dot_version], [2.26.0], - [AC_MSG_RESULT([no]) - AC_MSG_ERROR([Graphviz dot $dot_version too old. Graphviz 2.26+ required for documentation build. Install required graphviz version or disable the documentation using --disable-documentation])], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([yes])]) - - AC_MSG_CHECKING([for docbook stylesheets]) - DOCS_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl - AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc], - AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$DOCS_STYLESHEET" > /dev/null 2>&1`], - [HAVE_DOCS_STYLESHEET=yes])) - if test "x$HAVE_DOCS_STYLESHEET" != "xyes"; then - AC_MSG_RESULT([no]) - AC_MSG_ERROR([Documentation build requested but docbook-xsl stylesheets are not found. Install the docbook-xsl package or disable the documentation using --disable-documentation]) - fi - - AC_MSG_RESULT([yes]) - AC_SUBST(DOCS_STYLESHEET) - - AC_CONFIG_FILES([ - doc/doxygen/wayland.doxygen - ]) - -fi -AM_CONDITIONAL([HAVE_XMLTO], [test "x$XMLTO" != "x"]) - -AC_CONFIG_FILES([Makefile - cursor/wayland-cursor.pc - cursor/wayland-cursor-uninstalled.pc - doc/Makefile - doc/publican/Makefile - doc/doxygen/Makefile - egl/wayland-egl.pc - egl/wayland-egl-backend.pc - src/wayland-server-uninstalled.pc - src/wayland-client-uninstalled.pc - src/wayland-scanner-uninstalled.pc - src/wayland-server.pc - src/wayland-client.pc - src/wayland-scanner.pc - src/wayland-version.h]) -AC_OUTPUT diff --git a/cursor/wayland-cursor-uninstalled.pc.in b/cursor/wayland-cursor-uninstalled.pc.in deleted file mode 100644 index f52b1131..00000000 --- a/cursor/wayland-cursor-uninstalled.pc.in +++ /dev/null @@ -1,8 +0,0 @@ -libdir=@abs_builddir@/.libs -includedir=@abs_srcdir@ - -Name: Wayland Cursor -Description: Wayland cursor helper library (not installed) -Version: @WAYLAND_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lwayland-cursor diff --git a/cursor/wayland-cursor.pc.in b/cursor/wayland-cursor.pc.in deleted file mode 100644 index fbbf5fff..00000000 --- a/cursor/wayland-cursor.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: Wayland Cursor -Description: Wayland cursor helper library -Version: @WAYLAND_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lwayland-cursor diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index 0b1c4f20..00000000 --- a/doc/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = doxygen publican diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am deleted file mode 100644 index 86fd8bf7..00000000 --- a/doc/doxygen/Makefile.am +++ /dev/null @@ -1,113 +0,0 @@ - -.SUFFIXES = .gv .png .map - -noinst_DATA = \ - xml/Client/index.xml \ - xml/Cursor/index.xml \ - xml/Server/index.xml \ - html/Client/index.html \ - html/Cursor/index.html \ - html/Server/index.html -dist_noinst_DATA = wayland.doxygen.in - -scanned_src_files_shared = \ - $(top_srcdir)/src/wayland-util.h - -scanned_src_files_Client = \ - $(scanned_src_files_shared) \ - $(top_srcdir)/src/wayland-client.c \ - $(top_srcdir)/src/wayland-client.h \ - $(top_srcdir)/src/wayland-client-core.h - -scanned_src_files_Cursor = \ - $(top_srcdir)/cursor/wayland-cursor.c \ - $(top_srcdir)/cursor/wayland-cursor.h - -scanned_src_files_Server = \ - $(scanned_src_files_shared) \ - $(top_srcdir)/src/event-loop.c \ - $(top_srcdir)/src/wayland-server.c \ - $(top_srcdir)/src/wayland-server.h \ - $(top_srcdir)/src/wayland-server-core.h \ - $(top_srcdir)/src/wayland-shm.c - -scanned_src_files_man = \ - $(scanned_src_files_Server) \ - $(top_srcdir)/src/wayland-client.c \ - $(top_srcdir)/src/wayland-client.h \ - $(top_srcdir)/src/wayland-client-core.h - -extra_doxygen = \ - mainpage.dox - -extra_doxygen_Server = \ - $(top_builddir)/protocol/wayland-server-protocol.h \ - $(extra_doxygen) - -extra_doxygen_Client = \ - $(top_builddir)/protocol/wayland-client-protocol.h \ - $(extra_doxygen) - -extra_doxygen_Cursor = \ - $(extra_doxygen) - -diagramsdir := $(srcdir)/dot -diagramssrc := $(wildcard $(diagramsdir)/*.gv) -diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png)) -diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map)) - -# find all man/man3/wl_foo.3 pages -# for this to work, we need to create them before the man target (hence -# all-local below) -dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n") - -# Listing various directories that might need to be created. -alldirsrel := xml xml/Client xml/Server xml/Cursor man/man3 html/Client html/Server html/Cursor -alldirs := $(patsubst %,$(CURDIR)/%,$(alldirsrel)) - -$(diagrams): $(diagramssrc) - -$(diagram_maps): $(diagramssrc) - -xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/xml/% - $(AM_V_GEN)(cat wayland.doxygen; \ - echo "GENERATE_XML=YES"; \ - echo "XML_OUTPUT=xml/$*"; \ - echo "INPUT= $(scanned_src_files_$*)"; \ - ) | $(DOXYGEN) - - -html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/html/% - $(AM_V_GEN)(cat wayland.doxygen; \ - echo "PROJECT_NAME=\"Wayland $* API\""; \ - echo "GENERATE_HTML=YES"; \ - echo "HTML_OUTPUT=html/$*"; \ - echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \ - ) | $(DOXYGEN) - - -man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | $(CURDIR)/man/man3 - $(AM_V_GEN)(cat wayland.doxygen; \ - echo "GENERATE_MAN=YES"; \ - echo "MAN_OUTPUT=man"; \ - echo "JAVADOC_AUTOBRIEF=NO"; \ - echo "INPUT= $(scanned_src_files_man)"; \ - ) | $(DOXYGEN) - - -xml/%.png: $(diagramsdir)/%.gv | $(CURDIR)/xml - $(AM_V_GEN)$(DOT) -Tpng -o$@ $< - -xml/%.map: $(diagramsdir)/%.gv | $(CURDIR)/xml - $(AM_V_GEN)$(DOT) -Tcmapx_np -o$@ $< - -# general rule to create one of the listed directories. -$(alldirs): - $(AM_V_GEN)$(MKDIR_P) $@ - -# there is no man-local -all-local: man/man3/wl_display.3 - -clean-local: - rm -rf xml/ - rm -rf html/ - rm -rf man/ - -EXTRA_DIST = $(diagramssrc) diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am deleted file mode 100644 index e861fe67..00000000 --- a/doc/publican/Makefile.am +++ /dev/null @@ -1,169 +0,0 @@ -# Documentation is built with xmlto, but some of the recipes in here are -# leftovers from building with Publican (https://fedorahosted.org/publican/) -# -# How this build works: -# * the main target is Wayland, documentation ends up in $(builddir)/Wayland/ -# * hand-written chapters and CSS files are located in sources. These are -# copied into $(builddir)/en-US/ -# * ProtocolSpec.xml is generated from $(top_srcdir)/protocol/wayland.xml, -# changed into docbook via XSLT and saved in $(builddir)/en-US/ -# * ProtocolInterfaces.xml, same as above, uses a different XSLT -# * *API.xml is generated from the doxygen output and saved in -# $(builddir)/en-US -# * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US - -doxydir := $(top_builddir)/doc/doxygen -html_destdir := $(builddir)/Wayland/en-US/html - -publican_sources = \ - $(srcdir)/sources/Wayland.ent \ - $(srcdir)/sources/Wayland.xml \ - $(srcdir)/sources/Book_Info.xml \ - $(srcdir)/sources/Author_Group.xml \ - $(srcdir)/sources/Foreword.xml \ - $(srcdir)/sources/Preface.xml \ - $(srcdir)/sources/Revision_History.xml \ - $(srcdir)/sources/Protocol.xml \ - $(srcdir)/sources/Xwayland.xml \ - $(srcdir)/sources/Compositors.xml \ - $(srcdir)/sources/images/icon.svg \ - $(srcdir)/sources/images/wayland.png \ - $(srcdir)/sources/images/xwayland-architecture.png \ - $(srcdir)/sources/Client.xml \ - $(srcdir)/sources/Server.xml - -processed_sources := \ - $(srcdir)/sources/Architecture.xml \ - $(srcdir)/sources/Introduction.xml - -css_sources = \ - $(srcdir)/sources/css/brand.css \ - $(srcdir)/sources/css/common.css \ - $(srcdir)/sources/css/default.css \ - $(srcdir)/sources/css/epub.css \ - $(srcdir)/sources/css/print.css - -img_sources = \ - $(srcdir)/sources/images/icon.svg \ - $(srcdir)/sources/images/wayland.png \ - $(srcdir)/sources/images/xwayland-architecture.png - -doxygen_img_sources := \ - $(doxydir)/xml/wayland-architecture.png \ - $(doxydir)/xml/x-architecture.png - -map_sources := \ - $(doxydir)/xml/x-architecture.map \ - $(doxydir)/xml/wayland-architecture.map - -if HAVE_XMLTO -if HAVE_XSLTPROC -noinst_DATA = $(builddir)/Wayland $(publican_targets) -XMLTO_PARAM = \ - --skip-validation \ - --stringparam chunk.section.depth=0 \ - --stringparam toc.section.depth=1 \ - --stringparam html.stylesheet=css/default.css - -# Listing various directories that might need to be created. -alldirs := $(builddir)/en-US $(builddir)/en-US/images $(html_destdir) $(html_destdir)/css $(html_destdir)/images - - -html_css_targets = $(addprefix $(html_destdir)/css/,$(notdir $(css_sources))) -html_img_targets = $(addprefix $(html_destdir)/images/,$(notdir $(img_sources))) -doxygen_img_targets := $(doxygen_img_sources:$(doxydir)/xml/%=$(html_destdir)/images/%) -map_targets := $(map_sources:$(doxydir)/xml/%=$(builddir)/en-US/images/%) -processed_targets := $(processed_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) - -$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) $(processed_targets) $(doxygen_img_targets) | $(builddir)/en-US - $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html $(builddir)/en-US/Wayland.xml -o $(html_destdir) - @touch $@ - -$(html_destdir)/css/%: $(srcdir)/sources/css/% | $(html_destdir)/css - $(AM_V_GEN)cp -f $< $@ - -$(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images - $(AM_V_GEN)cp -f $< $@ - -$(html_destdir)/images/%: $(doxydir)/xml/% | $(html_destdir)/images - $(AM_V_GEN)cp -f $< $@ - -pubdir = $(docdir)/Wayland/en-US - -publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \ - $(builddir)/en-US/ProtocolSpec.xml \ - $(builddir)/en-US/ProtocolInterfaces.xml \ - $(builddir)/en-US/ClientAPI.xml \ - $(builddir)/en-US/ServerAPI.xml - -# The Protocol.xml is purely generated and required before running publican -$(builddir)/en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-to-docbook.xsl | $(builddir)/en-US - $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-to-docbook.xsl \ - $(top_srcdir)/protocol/wayland.xml > $@ - -$(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl | $(builddir)/en-US - $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-interfaces-to-docbook.xsl \ - $(top_srcdir)/protocol/wayland.xml > $@ - -# * use doxygen's combine.xslt to merge the xml files into one single file -# * pipe that through the doxygen-to-publican stylesheet -$(builddir)/en-US/%API.xml: $(doxydir)/xml/%/index.xml $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US - $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \ - $(doxydir)/xml/$*/index.xml | \ - $(XSLTPROC) --stringparam which $* \ - $(srcdir)/doxygen-to-publican.xsl - > $@ - -# Copy the sources source files into en-US destination -# This is required for out-of-source-tree build as publican does not allow us -# to specify the location of the source code. -$(builddir)/en-US/%: $(srcdir)/sources/% $(publican_sources) | $(builddir)/en-US/images - $(AM_V_GEN)cp -f $< $@ - $(AM_V_at)chmod a+w $@ - -$(builddir)/en-US/images/%: $(doxydir)/xml/% | $(builddir)/en-US/images - $(AM_V_GEN)cp -f $< $@ - $(AM_V_at)chmod a+w $@ - -# More specific rule to override explicitly listed targets and perform xslt -# modifications on them. -# Note that we can't use $< as all targets must be there -$(processed_targets): $(processed_sources) $(map_targets) $(srcdir)/merge-mapcoords.xsl | $(builddir)/en-US/images - $(AM_V_GEN)$(XSLTPROC) --stringparam basedir $(builddir)/en-US \ - $(srcdir)/merge-mapcoords.xsl $(addprefix $(srcdir)/sources/,$(notdir $@)) > $@ - -# general rule to create one of the listed directories. -$(alldirs): - $(AM_V_GEN)$(MKDIR_P) $@ - -CLEANFILES = $(publican_targets) - -clean-local: - $(AM_V_at)rm -fr $(builddir)/en-US - $(AM_V_at)rm -fr $(builddir)/Wayland - -install-data-local: - test -z "$(pubdir)/html/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/css" - test -z "$(pubdir)/html/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/images" - list=`find $(builddir)/Wayland/en-US -type f`; \ - for p in $$list; do \ - echo " $(INSTALL_DATA) '$$p' '$(DESTDIR)$(docdir)/$$p'"; \ - $(INSTALL_DATA) "$$p" "$(DESTDIR)$(docdir)/$$p"; \ - done; - -uninstall-local: - @if test -n $(DESTDIR)$(docdir); then \ - if test -d $(DESTDIR)$(docdir); then \ - echo " rm -fr $(DESTDIR)$(docdir)/Wayland;"; \ - rm -fr $(DESTDIR)$(docdir)/Wayland; \ - fi; \ - fi; - -endif -endif - -EXTRA_DIST = \ - $(publican_sources) $(processed_sources) $(css_sources) $(img_sources) \ - protocol-to-docbook.xsl \ - protocol-interfaces-to-docbook.xsl \ - doxygen-to-publican.xsl \ - merge-mapcoords.xsl diff --git a/egl/wayland-egl-backend.h b/egl/wayland-egl-backend.h index 869c86fd..e5287b76 100644 --- a/egl/wayland-egl-backend.h +++ b/egl/wayland-egl-backend.h @@ -35,8 +35,8 @@ extern "C" { #endif /* - * NOTE: This version must be kept in sync with the Version field in the - * wayland-egl-backend.pc.in file. + * NOTE: This version must be kept in sync with the version field in the + * wayland-egl-backend pkgconfig file generated in meson.build. */ #define WL_EGL_WINDOW_VERSION 3 diff --git a/egl/wayland-egl-backend.pc.in b/egl/wayland-egl-backend.pc.in deleted file mode 100644 index 6cf0ed4d..00000000 --- a/egl/wayland-egl-backend.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -includedir=@includedir@ - -Name: wayland-egl-backend -Description: Backend wayland-egl interface -Version: 3 -Libs: -Cflags: -I${includedir} diff --git a/egl/wayland-egl.pc.in b/egl/wayland-egl.pc.in deleted file mode 100644 index 2e2d4c49..00000000 --- a/egl/wayland-egl.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: wayland-egl -Description: Frontend wayland-egl library -Version: 18.1.0 -Requires: wayland-client -Libs: -L${libdir} -lwayland-egl -Cflags: -I${includedir} diff --git a/m4/.gitignore b/m4/.gitignore deleted file mode 100644 index 38066ddf..00000000 --- a/m4/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -libtool.m4 -ltoptions.m4 -ltsugar.m4 -ltversion.m4 -lt~obsolete.m4 diff --git a/m4/weston.m4 b/m4/weston.m4 deleted file mode 100644 index 636f9fb0..00000000 --- a/m4/weston.m4 +++ /dev/null @@ -1,37 +0,0 @@ -dnl -dnl Copyright © 2016 Quentin “Sardem FF7” Glidic -dnl -dnl Permission is hereby granted, free of charge, to any person obtaining a -dnl copy of this software and associated documentation files (the "Software"), -dnl to deal in the Software without restriction, including without limitation -dnl the rights to use, copy, modify, merge, publish, distribute, sublicense, -dnl and/or sell copies of the Software, and to permit persons to whom the -dnl Software is furnished to do so, subject to the following conditions: -dnl -dnl The above copyright notice and this permission notice (including the next -dnl paragraph) shall be included in all copies or substantial portions of the -dnl Software. -dnl -dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -dnl DEALINGS IN THE SOFTWARE. -dnl - -dnl WESTON_SEARCH_LIBS(PREFIX, search-libs, function, [action-if-found], [action-if-not-found], [other-libraries]) -dnl WESTON_SEARCH_LIBS is a wrapper around AC_SEARCH_LIBS with a little difference: -dnl action-if-found is called even if no library is required -AC_DEFUN([WESTON_SEARCH_LIBS], [ - weston_save_LIBS=${LIBS} - AC_SEARCH_LIBS([$3], [$2], [$4], [$5], [$6]) - AS_CASE([${ac_cv_search_][$3][}], - ['none required'], [$4], - [no], [], - [$1][_LIBS=${ac_cv_search_][$3][}] - ) - AC_SUBST([$1][_LIBS]) - LIBS=${weston_save_LIBS} -]) diff --git a/releasing.txt b/releasing.txt index 1481f7cd..db879715 100644 --- a/releasing.txt +++ b/releasing.txt @@ -3,16 +3,16 @@ To make a release of Wayland, follow these steps. 0. Verify the test suites and codebase checks pass. All of the tests should either pass or skip. - $ make check + $ ninja -C build/ test - 1. Update the first stanza of configure.ac to the intended version. + 1. Update the first stanza of meson.build to the intended version. Then commit your changes: $ export RELEASE_NUMBER="x.y.z" $ export RELEASE_NAME="[alpha|beta|RC1|RC2|official|point]" $ git status - $ git commit configure.ac -m "configure.ac: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release" + $ git commit meson.build -m "build: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release" $ git push 2. Run the release.sh script to generate the tarballs, sign and @@ -69,9 +69,9 @@ development early). $ git branch x.y [sha] $ git push origin x.y -The master branch's configure.ac version should always be (at least) +The master branch's meson.build version should always be (at least) x.y.90, with x.y being the most recent stable branch. The stable -branch's configure.ac version is just whatever was most recently +branch's meson.build version is just whatever was most recently released from that branch. For stable branches, we commit fixes to master first, then cherry-pick diff --git a/src/wayland-client-uninstalled.pc.in b/src/wayland-client-uninstalled.pc.in deleted file mode 100644 index 6fd0ce6d..00000000 --- a/src/wayland-client-uninstalled.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -libdir=@abs_builddir@/.libs -includedir=@abs_srcdir@ -protocoldir=@abs_top_builddir@/protocol - -Name: Wayland Client -Description: Wayland client side library (not installed) -Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} -I${protocoldir} -Libs: -L${libdir} -lwayland-client diff --git a/src/wayland-client.pc.in b/src/wayland-client.pc.in deleted file mode 100644 index eef61da5..00000000 --- a/src/wayland-client.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -datarootdir=@datarootdir@ -pkgdatadir=@datadir@/@PACKAGE@ -libdir=@libdir@ -includedir=@includedir@ - -Name: Wayland Client -Description: Wayland client side library -Version: @WAYLAND_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lwayland-client diff --git a/src/wayland-scanner-uninstalled.pc.in b/src/wayland-scanner-uninstalled.pc.in deleted file mode 100644 index 45597998..00000000 --- a/src/wayland-scanner-uninstalled.pc.in +++ /dev/null @@ -1,6 +0,0 @@ -pkgdatadir=@abs_top_srcdir@ -wayland_scanner=@abs_top_builddir@/wayland-scanner - -Name: Wayland Scanner -Description: Wayland scanner (not installed) -Version: @PACKAGE_VERSION@ diff --git a/src/wayland-scanner.pc.in b/src/wayland-scanner.pc.in deleted file mode 100644 index 7b2a4c92..00000000 --- a/src/wayland-scanner.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -datarootdir=@datarootdir@ -pkgdatadir=@datadir@/@PACKAGE@ -wayland_scanner=@bindir@/wayland-scanner - -Name: Wayland Scanner -Description: Wayland scanner -Version: @WAYLAND_VERSION@ diff --git a/src/wayland-server-uninstalled.pc.in b/src/wayland-server-uninstalled.pc.in deleted file mode 100644 index 6b6e6037..00000000 --- a/src/wayland-server-uninstalled.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -libdir=@abs_builddir@/.libs -includedir=@abs_srcdir@ -protocoldir=@abs_top_builddir@/protocol - -Name: Wayland Server -Description: Server side implementation of the Wayland protocol (not installed) -Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} -I${protocoldir} -Libs: -L${libdir} -lwayland-server diff --git a/src/wayland-server.pc.in b/src/wayland-server.pc.in deleted file mode 100644 index 50dff533..00000000 --- a/src/wayland-server.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -datarootdir=@datarootdir@ -pkgdatadir=@datadir@/@PACKAGE@ -libdir=@libdir@ -includedir=@includedir@ - -Name: Wayland Server -Description: Server side implementation of the Wayland protocol -Version: @WAYLAND_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lwayland-server From 1349d3d15bf7d100d0eae52d976a121d2dcf32ce Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 19 Mar 2021 11:24:05 +0000 Subject: [PATCH 0704/1152] Use MAP_FAILED instead of (void *) -1 While MAP_FAILED is generally defined to that value, we should not be relying on implementation details of system headers. Signed-off-by: Alex Richardson Reviewed-by: Simon Ser --- src/wayland-shm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index b85e5a79..7320bc99 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -511,10 +511,8 @@ sigbus_handler(int signum, siginfo_t *info, void *context) sigbus_data->fallback_mapping_used = 1; /* This should replace the previous mapping */ - if (mmap(pool->data, pool->size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, - 0, 0) == (void *) -1) { + if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0) == MAP_FAILED) { reraise_sigbus(); return; } From d224e6ccf38a4970f10713b0dab63e6747162698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 26 Mar 2021 17:21:07 +0100 Subject: [PATCH 0705/1152] ci: Use ci-fairy to check for Signed-off-by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- .gitlab-ci.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d2b07437..a0e2ee53 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -.templates_sha: &template_sha bd8010dd0123d3f0dda4ef691078566af2842613 # see https://docs.gitlab.com/ee/ci/yaml/#includefile +.templates_sha: &template_sha 290b79e0e78eab67a83766f4e9691be554fc4afd # see https://docs.gitlab.com/ee/ci/yaml/#includefile include: @@ -6,9 +6,14 @@ include: - project: 'freedesktop/ci-templates' ref: *template_sha file: '/templates/debian.yml' + # ci-fairy template + - project: 'freedesktop/ci-templates' + ref: *template_sha + file: '/templates/ci-fairy.yml' stages: + - review - prep - build @@ -32,6 +37,19 @@ variables: FDO_DISTRIBUTION_EXEC: $DEBIAN_EXEC +check-commit: + extends: + - .fdo.ci-fairy + stage: review + script: + - ci-fairy check-commits --signed-off-by --junit-xml=results.xml + variables: + GIT_DEPTH: 100 + artifacts: + reports: + junit: results.xml + + debian:buster@container-prep: extends: - .debian.buster From e4659ffbf5ee32cb55a045bf63ae1e81c0c2938c Mon Sep 17 00:00:00 2001 From: Michael Weiss Date: Fri, 2 Apr 2021 19:26:57 +0200 Subject: [PATCH 0706/1152] meson: Only require expat when building wayland-scanner This code is only required for building wayland-scanner so it should be scoped accordingly. libxml-2.0 will only be required if both "scanner" and "dtd_validation" are set to true. Signed-off-by: Michael Weiss --- meson.build | 7 ------- src/meson.build | 10 +++++++++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index dd5774a8..12b4641a 100644 --- a/meson.build +++ b/meson.build @@ -66,13 +66,6 @@ if get_option('libraries') endif endif -scanner_deps = [ dependency('expat') ] - -if get_option('dtd_validation') - scanner_deps += dependency('libxml-2.0') - config_h.set('HAVE_LIBXML', 1) -endif - configure_file( output: 'config.h', configuration: config_h, diff --git a/src/meson.build b/src/meson.build index d91c503e..b6b248c0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -26,6 +26,14 @@ wayland_util_dep = declare_dependency( if get_option('scanner') # wayland-scanner + scanner_deps = [ dependency('expat') ] + scanner_args = [ '-include', 'config.h' ] + + if get_option('dtd_validation') + scanner_deps += dependency('libxml-2.0') + scanner_args += '-DHAVE_LIBXML=1' + endif + configure_file( input: '../protocol/wayland.dtd', output: 'wayland.dtd.embed', @@ -38,7 +46,7 @@ if get_option('scanner') wayland_scanner = executable( 'wayland-scanner', wayland_scanner_sources, - c_args: [ '-include', 'config.h' ], + c_args: scanner_args, include_directories: wayland_scanner_includes, dependencies: [ scanner_deps, wayland_util_dep, ], install: true From e88193492771f6d3c9f6d9d7b9b2b21b1a04e92d Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 18 Mar 2021 10:45:50 +0000 Subject: [PATCH 0707/1152] os-wrappers-test.c: Correctly forward arguments to fcntl We can't just unconditionally read the optional arguments (and also read it as a void* despite actually being an int). While this happens to work on most architectures because the first few variadic arguments are passed in registers, this is non-portable and causes a crash on architectures that set bounds on variadic function arguments (for example CHERI-enabled architectures). It could also cause problems on big-endian architectures that pass variadic arguments on the stack rather than in registers. For CHERI-MIPS, reading sizeof(void*) causes a read of 16 bytes from the bounded varargs capability. This always crashes since even calls with the optional argument only have 4 bytes available. Signed-off-by: Alex Richardson Reviewed-by: Simon Ser --- tests/os-wrappers-test.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 102622c3..4d5de31b 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -85,7 +85,8 @@ __attribute__ ((visibility("default"))) int fcntl(int fd, int cmd, ...) { va_list ap; - void *arg; + int arg; + int has_arg; wrapped_calls_fcntl++; @@ -93,12 +94,27 @@ fcntl(int fd, int cmd, ...) errno = EINVAL; return -1; } + switch (cmd) { + case F_DUPFD_CLOEXEC: + case F_DUPFD: + case F_SETFD: + va_start(ap, cmd); + arg = va_arg(ap, int); + has_arg = 1; + va_end(ap); + break; + case F_GETFD: + has_arg = 0; + break; + default: + fprintf(stderr, "Unexpected fctnl cmd %d\n", cmd); + abort(); + } - va_start(ap, cmd); - arg = va_arg(ap, void*); - va_end(ap); - - return real_fcntl(fd, cmd, arg); + if (has_arg) { + return real_fcntl(fd, cmd, arg); + } + return real_fcntl(fd, cmd); } __attribute__ ((visibility("default"))) ssize_t From 34306efeb261f8466ad427a61cdae3272b8bae4d Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 18 Mar 2021 10:46:55 +0000 Subject: [PATCH 0708/1152] Change wl_os_dupfd_cloexec minfd to be int The fcntl() argument is defined to be an int and not a long. This does not matter on most architectures since the value is passed in registers, but it causes issues on big-endian architectures that pass variadic arguments on the stack. Signed-off-by: Alex Richardson Reviewed-by: Simon Ser --- src/wayland-os.c | 2 +- src/wayland-os.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-os.c b/src/wayland-os.c index 93b6f5fc..1e4a23db 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -73,7 +73,7 @@ wl_os_socket_cloexec(int domain, int type, int protocol) } int -wl_os_dupfd_cloexec(int fd, long minfd) +wl_os_dupfd_cloexec(int fd, int minfd) { int newfd; diff --git a/src/wayland-os.h b/src/wayland-os.h index f51efaa6..af376405 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -30,7 +30,7 @@ int wl_os_socket_cloexec(int domain, int type, int protocol); int -wl_os_dupfd_cloexec(int fd, long minfd); +wl_os_dupfd_cloexec(int fd, int minfd); ssize_t wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags); From 4c2105312379b62dc84f6eaaf26e2ab293d51b92 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Fri, 16 Apr 2021 02:32:38 -0600 Subject: [PATCH 0709/1152] meson: only require cpp for tests Signed-off-by: James Hilliard --- meson.build | 2 +- tests/meson.build | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 12b4641a..cdb66bcb 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project( - 'wayland', 'c', 'cpp', + 'wayland', 'c', version: '1.19.90', license: 'MIT', meson_version: '>= 0.52.1', diff --git a/tests/meson.build b/tests/meson.build index a32ac508..2e11af4e 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -64,15 +64,17 @@ executable( dependencies: test_runner_dep ) -test( - 'cpp-compile-test', - executable( +if add_languages('cpp') + test( 'cpp-compile-test', - 'cpp-compile-test.cpp', - wayland_server_protocol_h, - include_directories: src_inc + executable( + 'cpp-compile-test', + 'cpp-compile-test.cpp', + wayland_server_protocol_h, + include_directories: src_inc + ) ) -) +endif sed_path = find_program('sed').path() From 88f1605a826ca0c2ff02be6f4cf9ecabf68e8341 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Tue, 3 Mar 2020 15:27:51 -0700 Subject: [PATCH 0710/1152] build: add option to disable tests When building for a product, tests are not needed. Besides, one test requires a C++ compiler, which is not always available. So, add an option to configure to disable building tests altogether. Signed-off-by: "Yann E. MORIN" Signed-off-by: Alexey Brodkin Signed-off-by: James Hilliard --- meson.build | 4 +++- meson_options.txt | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cdb66bcb..714a86d8 100644 --- a/meson.build +++ b/meson.build @@ -84,7 +84,9 @@ subdir('src') if get_option('libraries') subdir('cursor') subdir('egl') - subdir('tests') + if get_option('tests') + subdir('tests') + endif if get_option('documentation') subdir('doc') endif diff --git a/meson_options.txt b/meson_options.txt index de588d13..4433fa0f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,6 +6,10 @@ option('scanner', description: 'Compile wayland-scanner binary', type: 'boolean', value: 'true') +option('tests', + description: 'Compile Wayland tests', + type: 'boolean', + value: 'true') option('documentation', description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)', type: 'boolean', From 0aebb5b94d6c9ba5e5b1440cb57060d9063e202d Mon Sep 17 00:00:00 2001 From: Alexander Dunaev Date: Wed, 17 Feb 2021 15:44:00 +0700 Subject: [PATCH 0711/1152] cursor: add one more directory to XCURSORPATH The user may install cursor themes manually, and the desktop environment may provide a special directory for storing them. For instance, GTK puts those themes into ~/.local/share/icons, and many Linux distributions suggest using that directory for user-specific themes. However, users of libwayland-cursor cannot load these themes using the API provided by the library because the latter does not look into that directory. This patch adds ~/.local/share/icons to the search path, so user-specific themes can be loaded through the API provided by libwayland-cursor. Signed-off-by: Alexander Dunaev Reviewed-by: Emmanuel Gil Peyrot Reviewed-by: Simon Ser --- cursor/xcursor.c | 50 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 1f1360fb..3b35f1cc 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -621,16 +621,43 @@ XcursorFileLoadImages (FILE *file, int size) #define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR #endif -static const char * +#define XDG_DATA_HOME_FALLBACK "~/.local/share" +#define CURSORDIR "/icons" + +/** Get search path for cursor themes + * + * This function builds the list of directories to look for cursor + * themes in. The format is PATH-like: directories are separated by + * colons. + * + * The memory block returned by this function is allocated on the heap + * and must be freed by the caller. + */ +static char * XcursorLibraryPath (void) { - static const char *path; + const char *env_var; + char *path = NULL; + int pathlen = 0; - if (!path) + env_var = getenv ("XCURSOR_PATH"); + if (env_var) { - path = getenv ("XCURSOR_PATH"); - if (!path) - path = XCURSORPATH; + path = strdup (env_var); + } + else + { + env_var = getenv ("XDG_DATA_HOME"); + if (env_var) { + pathlen = strlen (env_var) + strlen (CURSORDIR ":" XCURSORPATH) + 1; + path = malloc (pathlen); + snprintf (path, pathlen, "%s%s", env_var, + CURSORDIR ":" XCURSORPATH); + } + else + { + path = strdup (XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); + } } return path; } @@ -803,6 +830,7 @@ XcursorScanTheme (const char *theme, const char *name) const char *path; char *inherits = NULL; const char *i; + char *xcursor_path; if (!theme || !name) return NULL; @@ -810,7 +838,8 @@ XcursorScanTheme (const char *theme, const char *name) /* * Scan this theme */ - for (path = XcursorLibraryPath (); + xcursor_path = XcursorLibraryPath (); + for (path = xcursor_path; path && f == NULL; path = _XcursorNextPath (path)) { @@ -842,6 +871,7 @@ XcursorScanTheme (const char *theme, const char *name) f = XcursorScanTheme (i, name); if (inherits != NULL) free (inherits); + free (xcursor_path); return f; } @@ -940,11 +970,13 @@ xcursor_load_theme(const char *theme, int size, char *full, *dir; char *inherits = NULL; const char *path, *i; + char *xcursor_path; if (!theme) theme = "default"; - for (path = XcursorLibraryPath(); + xcursor_path = XcursorLibraryPath(); + for (path = xcursor_path; path; path = _XcursorNextPath(path)) { dir = _XcursorBuildThemeDir(path, theme); @@ -975,4 +1007,6 @@ xcursor_load_theme(const char *theme, int size, if (inherits) free(inherits); + + free (xcursor_path); } From ed55438366e93d70867e3ba6b80978673e536fc0 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sun, 2 May 2021 21:35:23 +0200 Subject: [PATCH 0712/1152] cursor: fix CVE-2013-2003 The libXcursor fix for CVE-2013-2003 has never been imported into wayland, leaving it vulnerable to it. Changing the argument type to an unsigned type is an effective merge of Ilja Van Sprundel's commit in libXcursor. Signed-off-by: Tobias Stoeckmann --- cursor/xcursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 3b35f1cc..0506680f 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -300,7 +300,7 @@ _XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) } static XcursorFileHeader * -_XcursorFileHeaderCreate (int ntoc) +_XcursorFileHeaderCreate (XcursorUInt ntoc) { XcursorFileHeader *fileHeader; From 208fc99e66677fed61ba97382025f95db737696a Mon Sep 17 00:00:00 2001 From: Nick Diego Yamane Date: Wed, 28 Apr 2021 11:34:05 -0400 Subject: [PATCH 0713/1152] Document serial param usage in wl_pointer.set_cursor Serial is supposed to contain the latest wl_pointer.enter value received by clients but it was not even mentioned in the docs, so add it to avoid misinterpretations. Signed-off-by: Nick Diego Yamane --- protocol/wayland.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 61e0366d..9955d247 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1905,6 +1905,10 @@ wl_surface is no longer used as the cursor. When the use as a cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. + + The serial parameter must match the latest wl_pointer.enter + serial number sent to the client. Otherwise the request will be + ignored. Date: Fri, 7 May 2021 11:00:43 +0300 Subject: [PATCH 0714/1152] src: Add missing new lines to log messages Signed-off-by: Marius Vlad --- src/connection.c | 2 +- src/event-loop.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/connection.c b/src/connection.c index d0c7d9fc..69190a1b 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1049,7 +1049,7 @@ copy_fds_to_connection(struct wl_closure *closure, fd = closure->args[i].h; if (wl_connection_put_fd(connection, fd)) { wl_log("request could not be marshaled: " - "can't send file descriptor"); + "can't send file descriptor\n"); return -1; } closure->args[i].h = -1; diff --git a/src/event-loop.c b/src/event-loop.c index 339ff197..c7c98b08 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -340,7 +340,7 @@ wl_timer_heap_reserve(struct wl_timer_heap *timers) new_space = timers->space >= 8 ? timers->space * 2 : 8; n = realloc(timers->data, (size_t)new_space * sizeof(*n)); if (!n) { - wl_log("Allocation failure when expanding timer list"); + wl_log("Allocation failure when expanding timer list\n"); return -1; } timers->data = n; @@ -361,7 +361,7 @@ wl_timer_heap_unreserve(struct wl_timer_heap *timers) if (timers->space >= 16 && timers->space >= 4 * timers->count) { n = realloc(timers->data, (size_t)timers->space / 2 * sizeof(*n)); if (!n) { - wl_log("Reallocation failure when shrinking timer list"); + wl_log("Reallocation failure when shrinking timer list\n"); return; } timers->data = n; @@ -942,8 +942,8 @@ post_dispatch_check(struct wl_event_loop *loop) dispatch_result = source->interface->dispatch(source, &ep); if (dispatch_result < 0) { - wl_log("Source dispatch function returned negative value!"); - wl_log("This would previously accidentally suppress a follow-up dispatch"); + wl_log("Source dispatch function returned negative value!\n"); + wl_log("This would previously accidentally suppress a follow-up dispatch\n"); } needs_recheck |= dispatch_result != 0; } From f452e41264387dee4fd737cbf1af58b34b53941b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 15 Dec 2020 20:35:25 +0100 Subject: [PATCH 0715/1152] build: replace assembly embedding with Python script This allows Meson to properly track dependencies and re-build the scanner when editing the dtd. We also stop depending on GNU as' .incbin and make the embedding less obscure. Signed-off-by: Simon Ser --- src/dtddata.S | 50 ------------------------------------------------- src/embed.py | 45 ++++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 12 ++++++++---- src/scanner.c | 10 +++++----- 4 files changed, 58 insertions(+), 59 deletions(-) delete mode 100644 src/dtddata.S create mode 100644 src/embed.py diff --git a/src/dtddata.S b/src/dtddata.S deleted file mode 100644 index 24050665..00000000 --- a/src/dtddata.S +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Avoid executable stack. - * from: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart - */ -#if defined(__linux__) && defined(__ELF__) -.section .note.GNU-stack,"",%progbits -#endif - -/* from: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967#comment-348129 */ - -.macro binfile name file - .p2align 2 - .globl \name\()_begin -\name\()_begin: - .incbin "\file" -\name\()_end: - .byte 0 - .p2align 2 - .globl \name\()_len -\name\()_len: - .int (\name\()_end - \name\()_begin) -.endm - -.section .rodata -binfile DTD_DATA src/wayland.dtd.embed diff --git a/src/embed.py b/src/embed.py new file mode 100644 index 00000000..abebb157 --- /dev/null +++ b/src/embed.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +""" +Simple C data embedder + +License: MIT + +Copyright (c) 2020 Simon Ser + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import sys + +if len(sys.argv) != 3: + print('usage: ' + sys.argv[0] + ' ', file=sys.stderr) + sys.exit(1) + +filename = sys.argv[1] +ident = sys.argv[2] + +with open(filename, 'rb') as f: + buf = f.read() + +print('static const char ' + ident + '[] = {\n\t', end='') +for i in range(len(buf)): + ch = buf[i:i+1] + print('0x' + ch.hex() + ', ', end='') +print('\n};') diff --git a/src/meson.build b/src/meson.build index b6b248c0..ec00d816 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,13 +34,17 @@ if get_option('scanner') scanner_args += '-DHAVE_LIBXML=1' endif - configure_file( + prog_embed = find_program('embed.py', native: true) + + embed_dtd = custom_target( + 'wayland.dtd.h', input: '../protocol/wayland.dtd', - output: 'wayland.dtd.embed', - copy: true + output: 'wayland.dtd.h', + command: [ prog_embed, '@INPUT@', 'wayland_dtd' ], + capture: true ) - wayland_scanner_sources = [ 'scanner.c', 'dtddata.S' ] + wayland_scanner_sources = [ 'scanner.c', embed_dtd ] wayland_scanner_includes = [ root_inc, protocol_inc ] wayland_scanner = executable( diff --git a/src/scanner.c b/src/scanner.c index 36ac905f..46bdfc22 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -41,9 +41,9 @@ #if HAVE_LIBXML #include -/* Embedded wayland.dtd file, see dtddata.S */ -extern char DTD_DATA_begin; -extern int DTD_DATA_len; +/* Embedded wayland.dtd file */ +/* static const char wayland_dtd[]; wayland.dtd */ +#include "wayland.dtd.h" #endif /* Expat must be included after libxml as both want to declare XMLCALL; see @@ -112,8 +112,8 @@ is_dtd_valid(FILE *input, const char *filename) if (!ctx || !dtdctx) abort(); - buffer = xmlParserInputBufferCreateMem(&DTD_DATA_begin, - DTD_DATA_len, + buffer = xmlParserInputBufferCreateMem(wayland_dtd, + sizeof(wayland_dtd), XML_CHAR_ENCODING_UTF8); if (!buffer) { fprintf(stderr, "Failed to init buffer for DTD.\n"); From f8bea2450d0fc1d68b22ed36b9e500afdd4026c7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 26 May 2021 12:00:17 +0200 Subject: [PATCH 0716/1152] protocol: drop reference to wl_drm Change the wl_drm reference to linux-dmabuf. wl_drm is a legacy, private Mesa protocol that shouldn't be used by regular clients. Signed-off-by: Simon Ser --- protocol/wayland.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 9955d247..acb85fdb 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -431,10 +431,11 @@ A buffer provides the content for a wl_surface. Buffers are - created through factory interfaces such as wl_drm, wl_shm or - similar. It has a width and a height and can be attached to a - wl_surface, but the mechanism by which a client provides and - updates the contents is defined by the buffer factory interface. + created through factory interfaces such as wl_shm, wp_linux_buffer_params + (from the linux-dmabuf protocol extension) or similar. It has a width and + a height and can be attached to a wl_surface, but the mechanism by which a + client provides and updates the contents is defined by the buffer factory + interface. From abcf1048e23525865c2ff43ce90bbdaa80524246 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Fri, 14 May 2021 13:06:15 +0200 Subject: [PATCH 0717/1152] cursor: fix crash with weird input files If a cursor file contains multiple images for the same size, this typically indicates an animation. The compositor weston uses wl_cursor_frame_and_duration to figure out at which time a specific image should be shown. The total delay is the sum of all image delays. But if all images have a delay of 0, the total delay is 0 as well. The code does not check for this special condition and triggers a floating point exception by eventually performing a modulo operation with 0. This, of course, could also happen if the sum of all image delays triggers an unsigned int overflow. But since a comment in the code already indicates that it does not try to "fix" handling of weird files, I would argue that it's "okay" if that happens. At least the program won't crash. Proof of Concept: install -D ~/.icons/poc/cursors base64 -d > ~/.icons/poc/cursors/left_ptr << EOF WGN1chAAAAAAAAEAAgAAAAIA/f8BAAAAKAAAAAIA/f8BAAAAKAAAACQAAAACAP3/AQAAAAEAAAAB AAAAAQAAAAEAAAABAAAAAAAAAAAAAAA= EOF cat > /tmp/weston.ini << EOF [shell] cursor-theme=poc EOF weston -c /tmp/weston.ini Signed-off-by: Tobias Stoeckmann --- cursor/wayland-cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 4e2dc502..7da70141 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -475,7 +475,7 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, uint32_t t; int i; - if (cursor->cursor.image_count == 1) { + if (cursor->cursor.image_count == 1 || cursor->total_delay == 0) { if (duration) *duration = 0; return 0; From ba0c63dee86cf94272c7763d711695fe3af0f210 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Jun 2021 16:22:54 +0200 Subject: [PATCH 0718/1152] shm: remove wl_shm_buffer.pool NULL checks wl_shm_buffer.pool is never set to NULL. The only time it's set is in shm_pool_create_buffer, and the pool is guaranteed to be non-NULL there. Signed-off-by: Simon Ser --- src/wayland-shm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 7320bc99..aa64ff38 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -124,8 +124,7 @@ destroy_buffer(struct wl_resource *resource) { struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource); - if (buffer->pool) - shm_pool_unref(buffer->pool, false); + shm_pool_unref(buffer->pool, false); free(buffer); } @@ -400,11 +399,6 @@ wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer) WL_EXPORT void * wl_shm_buffer_get_data(struct wl_shm_buffer *buffer) { - assert(buffer->pool); - - if (!buffer->pool) - return NULL; - if (buffer->pool->external_refcount && (buffer->pool->size != buffer->pool->new_size)) wl_log("Buffer address requested when its parent pool " From 3e897faa29d13bef6f9af31d4f2e89a526e60f4c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 26 May 2021 12:07:17 +0200 Subject: [PATCH 0719/1152] protocol: allow immediate wl_buffer.destroy if not re-used Allow wl_buffer objects to be destroyed without having to wait for wl_buffer.release if the underlying storage isn't going to be re-used. The main motivation for this is to avoid glitches when a client is torn down. When a client disconnects, all of its objects are destroyed in arbitrary order. However some compositors will still need to access the destroyed buffer's underlying storage afterwards, e.g. for visual effects (fade-out) or for atomic layout updates (wait for other clients to commit a new buffer before hiding the buffer). It's still incorrect for clients to destroy a wl_buffer and mutate the underlying storage without waiting for wl_buffer.release. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/185 --- protocol/wayland.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index acb85fdb..ef65714f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1435,9 +1435,12 @@ from the same backing storage or use wp_linux_buffer_release. Destroying the wl_buffer after wl_buffer.release does not change - the surface contents. However, if the client destroys the - wl_buffer before receiving the wl_buffer.release event, the surface - contents become undefined immediately. + the surface contents. Destroying the wl_buffer before wl_buffer.release + is allowed as long as the underlying buffer storage isn't re-used (this + can happen e.g. on client process termination). However, if the client + destroys the wl_buffer before receiving the wl_buffer.release event and + mutates the underlying buffer storage, the surface contents become + undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. From 4f53613e70cfc8eb23a91d289c79dc67f1114088 Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Tue, 22 Jun 2021 20:05:47 +1000 Subject: [PATCH 0720/1152] connection-test: Encode size in message headers correctly In these tests, message sizes are inconsistently encoded in either the upper or lower 16 bits of the second word of the message. Resolve this in favour of using the upper 16 bits, as this is how messages are supposed to be encoded, even though that aspect of message decoding isn't being tested here. Signed-off-by: Fergus Dall --- tests/connection-test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/connection-test.c b/tests/connection-test.c index c04845bb..669d73b1 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -394,7 +394,7 @@ demarshal(struct marshal_data *data, const char *format, struct wl_closure *closure; struct wl_map objects; struct wl_object object = { NULL, &func, 0 }; - int size = msg[1]; + int size = msg[1] >> 16; assert(write(data->s[1], msg, size) == size); assert(wl_connection_read(data->read_connection) == size); @@ -417,39 +417,39 @@ TEST(connection_demarshal) data.value.u = 8000; msg[0] = 400200; /* object id */ - msg[1] = 12; /* size = 12, opcode = 0 */ + msg[1] = 12 << 16; /* size = 12, opcode = 0 */ msg[2] = data.value.u; demarshal(&data, "u", msg, (void *) validate_demarshal_u); data.value.i = -557799; msg[0] = 400200; - msg[1] = 12; + msg[1] = 12 << 16; msg[2] = data.value.i; demarshal(&data, "i", msg, (void *) validate_demarshal_i); data.value.s = "superdude"; msg[0] = 400200; - msg[1] = 24; + msg[1] = 24 << 16; msg[2] = 10; memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "s", msg, (void *) validate_demarshal_s); data.value.s = "superdude"; msg[0] = 400200; - msg[1] = 24; + msg[1] = 24 << 16; msg[2] = 10; memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "?s", msg, (void *) validate_demarshal_s); data.value.i = wl_fixed_from_double(-90000.2390); msg[0] = 400200; - msg[1] = 12; + msg[1] = 12 << 16; msg[2] = data.value.i; demarshal(&data, "f", msg, (void *) validate_demarshal_f); data.value.s = NULL; msg[0] = 400200; - msg[1] = 12; + msg[1] = 12 << 16; msg[2] = 0; demarshal(&data, "?s", msg, (void *) validate_demarshal_s); From ccc9612e823601f9bb7675bf2b029fd6eed6ed7b Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Tue, 22 Jun 2021 19:31:26 +1000 Subject: [PATCH 0721/1152] connection: Handle non-nullable strings in wl_connection_demarshal Currently a null string passed into a non-nullable argument of a message will decode succesfully, probably resulting in the handler function crashing. Instead treat it the same way we do non-nullable objects and ids. Signed-off-by: Fergus Dall --- src/connection.c | 7 +++++++ tests/connection-test.c | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/connection.c b/src/connection.c index 69190a1b..ccbb9721 100644 --- a/src/connection.c +++ b/src/connection.c @@ -749,6 +749,13 @@ wl_connection_demarshal(struct wl_connection *connection, case 's': length = *p++; + if (length == 0 && !arg.nullable) { + wl_log("NULL string received on non-nullable " + "type, message %s(%s)\n", message->name, + message->signature); + errno = EINVAL; + goto err; + } if (length == 0) { closure->args[i].s = NULL; break; diff --git a/tests/connection-test.c b/tests/connection-test.c index 669d73b1..7220d875 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -553,6 +553,24 @@ expected_fail_demarshal(struct marshal_data *data, const char *format, assert(errno == expected_error); } +TEST(connection_demarshal_null_strings) +{ + struct marshal_data data; + uint32_t msg[3]; + + setup_marshal_data(&data); + + data.value.s = NULL; + msg[0] = 400200; /* object id */ + msg[1] = 12 << 16; /* size = 12, opcode = 0 */ + msg[2] = 0; /* string length = 0 */ + demarshal(&data, "?s", msg, (void *) validate_demarshal_s); + + expected_fail_demarshal(&data, "s", msg, EINVAL); + + release_marshal_data(&data); +} + /* These tests are verifying that the demarshaling code will gracefully handle * clients lying about string and array lengths and giving values near * UINT32_MAX. Before fixes f7fdface and f5b9e3b9 this test would crash on From 817fdb9009cd085a6e8b00a5fab207050cae5b1a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Jun 2021 16:35:30 +0200 Subject: [PATCH 0722/1152] shm: add safety assertions Catch any API mis-use with an assert. This should abort when the user calls unreferences the pool more times than it's referenced. Also change the refcount check to explicitly check for positive counts. That makes the condition more readable. Signed-off-by: Simon Ser --- src/wayland-shm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index aa64ff38..85204e4d 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -106,13 +106,15 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external) { if (external) { pool->external_refcount--; + assert(pool->external_refcount >= 0); if (pool->external_refcount == 0) shm_pool_finish_resize(pool); } else { pool->internal_refcount--; + assert(pool->internal_refcount >= 0); } - if (pool->internal_refcount + pool->external_refcount) + if (pool->internal_refcount + pool->external_refcount > 0) return; munmap(pool->data, pool->size); From 92038fa39497f0a481b38e623bd604feb6a01882 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 14 May 2021 16:25:07 +0300 Subject: [PATCH 0723/1152] CI: turn on ASan and UBSan I just noticed that libwayland test suite is ASan and UBSan clean, so let's turn that on in CI to avoid regressing. Signed-off-by: Pekka Paalanen --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a0e2ee53..1fadda90 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -70,7 +70,7 @@ build-native: - export BUILDDIR="$(pwd)/build-$BUILD_ID" - mkdir "$BUILDDIR" "$PREFIX" - cd "$BUILDDIR" - - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons .. + - meson --prefix="$PREFIX" -Db_sanitize=address,undefined -Dicon_directory=/usr/share/X11/icons .. - ninja -k0 test - ninja clean artifacts: From 767765d584df2c7ec759eab8edfaa79f31a2b692 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 29 Jun 2021 12:47:04 +0200 Subject: [PATCH 0724/1152] protocol: clarify wl_seat.name description Define the expected properties of the seat name. Signed-off-by: Simon Ser --- protocol/wayland.xml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index ef65714f..a87e9dda 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1842,9 +1842,22 @@ - In a multiseat configuration this can be used by the client to help - identify which physical devices the seat represents. Based on - the seat configuration used by the compositor. + In a multi-seat configuration the seat name can be used by clients to + help identify which physical devices the seat represents. + + The seat name is a UTF-8 string with no convention defined for its + contents. Each name is unique among all wl_seat globals. The name is + only guaranteed to be unique for the current compositor instance. + + The same seat names are used for all clients. Thus, the name can be + shared across processes to refer to a specific wl_seat global. + + The name event is sent after binding to the seat global. This event is + only sent once per seat object, and the name does not change over the + lifetime of the wl_seat global. + + Compositors may re-use the same seat name if the wl_seat global is + destroyed and re-created later. From 51d336ec140a8e44b74a5f3b3fcdf6e0038f9c86 Mon Sep 17 00:00:00 2001 From: James Legg Date: Thu, 3 Jun 2021 00:10:21 +0100 Subject: [PATCH 0725/1152] scanner: Use descriptions in entries entry may have a description according to the DTD. This is used in some protocols including xdg-shell. Fixes the code comment on an enum declaration using the description of the last enum that had one, adds the descriptions to the comments on enumerators, and avoids leaking the previously missing descriptions. Fixes #208 Signed-off-by: James Legg Signed-off-by: Pekka Paalanen --- src/scanner.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index 46bdfc22..64df6e8a 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -236,6 +236,7 @@ struct entry { char *summary; int since; struct wl_list link; + struct description *description; }; struct parse_context { @@ -245,6 +246,7 @@ struct parse_context { struct interface *interface; struct message *message; struct enumeration *enumeration; + struct entry *entry; struct description *description; char character_data[8192]; unsigned int character_data_length; @@ -542,6 +544,7 @@ free_entry(struct entry *entry) free(entry->uppercase_name); free(entry->value); free(entry->summary); + free_description(entry->description); free(entry); } @@ -884,6 +887,7 @@ start_element(void *data, const char *element_name, const char **atts) entry->summary = NULL; wl_list_insert(ctx->enumeration->entry_list.prev, &entry->link); + ctx->entry = entry; } else if (strcmp(element_name, "description") == 0) { if (summary == NULL) fail(&ctx->loc, "description without summary"); @@ -893,6 +897,8 @@ start_element(void *data, const char *element_name, const char **atts) if (ctx->message) ctx->message->description = description; + else if (ctx->entry) + ctx->entry->description = description; else if (ctx->enumeration) ctx->enumeration->description = description; else if (ctx->interface) @@ -1008,6 +1014,8 @@ end_element(void *data, const XML_Char *name) ctx->enumeration->name); } ctx->enumeration = NULL; + } else if (strcmp(name, "entry") == 0) { + ctx->entry = NULL; } else if (strcmp(name, "protocol") == 0) { struct interface *i; @@ -1364,10 +1372,17 @@ emit_enumerations(struct interface *interface) } printf("enum %s_%s {\n", interface->name, e->name); wl_list_for_each(entry, &e->entry_list, link) { - if (entry->summary || entry->since > 1) { + desc = entry->description; + if (entry->summary || entry->since > 1 || desc) { printf("\t/**\n"); if (entry->summary) printf("\t * %s\n", entry->summary); + if (desc) { + printf("\t * %s\n", desc->summary); + printf("\t *\n"); + if (desc->text) + desc_dump(desc->text, "\t * "); + } if (entry->since > 1) printf("\t * @since %d\n", entry->since); printf("\t */\n"); From b7153f2273d076adfdaaf6717cde1aca69da5f04 Mon Sep 17 00:00:00 2001 From: James Legg Date: Thu, 3 Jun 2021 00:10:22 +0100 Subject: [PATCH 0726/1152] tests: Test wayland-scanner with a description in an entry This previously would have caused a memory leak and incorrect comments. Signed-off-by: James Legg Signed-off-by: Pekka Paalanen --- tests/data/example-client.h | 20 ++++++++++---------- tests/data/example-server.h | 20 ++++++++++---------- tests/data/example.xml | 26 ++++++++++++++------------ 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/tests/data/example-client.h b/tests/data/example-client.h index d421af9d..9a2200a9 100644 --- a/tests/data/example-client.h +++ b/tests/data/example-client.h @@ -4095,16 +4095,6 @@ enum wl_pointer_axis { * from a "finger" source may be in a smooth coordinate space with * kinetic scrolling whereas a "wheel" source may be in discrete steps * of a number of lines. - * - * The "continuous" axis source is a device generating events in a - * continuous coordinate space, but using something other than a - * finger. One example for this source is button-based scrolling where - * the vertical motion of a device is converted to scroll events while - * a button is held down. - * - * The "wheel tilt" axis source indicates that the actual device is a - * wheel but the scroll event is not caused by a rotation but a - * (usually sideways) tilt of the wheel. */ enum wl_pointer_axis_source { /** @@ -4117,10 +4107,20 @@ enum wl_pointer_axis_source { WL_POINTER_AXIS_SOURCE_FINGER = 1, /** * continuous coordinate space + * + * A device generating events in a continuous coordinate space, + * but using something other than a finger. One example for this + * source is button-based scrolling where the vertical motion of a + * device is converted to scroll events while a button is held + * down. */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, /** * a physical wheel tilt + * + * Indicates that the actual device is a wheel but the scroll + * event is not caused by a rotation but a (usually sideways) tilt + * of the wheel. * @since 6 */ WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, diff --git a/tests/data/example-server.h b/tests/data/example-server.h index 3311c5d7..7cfa4e7a 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -3304,16 +3304,6 @@ enum wl_pointer_axis { * from a "finger" source may be in a smooth coordinate space with * kinetic scrolling whereas a "wheel" source may be in discrete steps * of a number of lines. - * - * The "continuous" axis source is a device generating events in a - * continuous coordinate space, but using something other than a - * finger. One example for this source is button-based scrolling where - * the vertical motion of a device is converted to scroll events while - * a button is held down. - * - * The "wheel tilt" axis source indicates that the actual device is a - * wheel but the scroll event is not caused by a rotation but a - * (usually sideways) tilt of the wheel. */ enum wl_pointer_axis_source { /** @@ -3326,10 +3316,20 @@ enum wl_pointer_axis_source { WL_POINTER_AXIS_SOURCE_FINGER = 1, /** * continuous coordinate space + * + * A device generating events in a continuous coordinate space, + * but using something other than a finger. One example for this + * source is button-based scrolling where the vertical motion of a + * device is converted to scroll events while a button is held + * down. */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, /** * a physical wheel tilt + * + * Indicates that the actual device is a wheel but the scroll + * event is not caused by a rotation but a (usually sideways) tilt + * of the wheel. * @since 6 */ WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, diff --git a/tests/data/example.xml b/tests/data/example.xml index 29b63be7..38feec30 100644 --- a/tests/data/example.xml +++ b/tests/data/example.xml @@ -1980,21 +1980,23 @@ from a "finger" source may be in a smooth coordinate space with kinetic scrolling whereas a "wheel" source may be in discrete steps of a number of lines. - - The "continuous" axis source is a device generating events in a - continuous coordinate space, but using something other than a - finger. One example for this source is button-based scrolling where - the vertical motion of a device is converted to scroll events while - a button is held down. - - The "wheel tilt" axis source indicates that the actual device is a - wheel but the scroll event is not caused by a rotation but a - (usually sideways) tilt of the wheel. - - + + + A device generating events in a continuous coordinate space, but + using something other than a finger. One example for this source + is button-based scrolling where the vertical motion of a device + is converted to scroll events while a button is held down. + + + + + Indicates that the actual device is a wheel but the scroll event is + not caused by a rotation but a (usually sideways) tilt of the wheel. + + From 8899310fc8ffc6f716ec6342ae415cb8692df855 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 13 Jul 2021 15:52:31 +0200 Subject: [PATCH 0727/1152] shm: document wl_shm_buffer The main motivation is to make it clear when a wl_shm_buffer is destroyed. Signed-off-by: Simon Ser --- src/wayland-shm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 85204e4d..671549c3 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -66,6 +66,15 @@ struct wl_shm_pool { bool sigbus_is_impossible; }; +/** \class wl_shm_buffer + * + * \brief A SHM buffer + * + * wl_shm_buffer provides a helper for accessing the contents of a wl_buffer + * resource created via the wl_shm interface. + * + * A wl_shm_buffer becomes invalid as soon as its #wl_resource is destroyed. + */ struct wl_shm_buffer { struct wl_resource *resource; int32_t width, height; From 13ccd1c4db4c3f26354530c3212b35462a002e06 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 13 Jul 2021 13:19:48 +0300 Subject: [PATCH 0728/1152] wayland-util: avoid memcpy(NULL) in wl_array_copy() The problem was found running Weston, with both Weston and Wayland built with ASan: ../../git/wayland/src/wayland-util.c:150:2: runtime error: null pointer passed as argument 1, which is declared to never be null ../../git/wayland/src/wayland-util.c:150:2: runtime error: null pointer passed as argument 2, which is declared to never be null This turns out to be caused by copying an empty array into an empty array. That seems to be completely valid thing to do, and wl_array_init() initializes the pointers to NULL and size to zero. Copying initialized arrays must always be valid. The error are caused by calling memcpy() with NULL pointers. It doesn't explode, because also the size is zero. Fix the problem by calling memcpy() only if size is not zero. This should keep things like copying an empty array into a non-empty array work. Signed-off-by: Pekka Paalanen --- src/wayland-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index d5973bf1..47d0baed 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -147,7 +147,9 @@ wl_array_copy(struct wl_array *array, struct wl_array *source) array->size = source->size; } - memcpy(array->data, source->data, source->size); + if (source->size > 0) + memcpy(array->data, source->data, source->size); + return 0; } From ada25fbd526dec116026cb2567a912b47890ad05 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 26 Sep 2020 21:14:16 -0400 Subject: [PATCH 0729/1152] client: print discarded events in debug log Before this patch, setting WAYLAND_DEBUG=1 or WAYLAND_DEBUG=client made a program log all requests sent and events that it processes. However, some events received are not processed. This can happen when a Wayland server sends an event to an object that does not exist, or was recently destroyed by the client program (either before the event was decoded, or after being decoded but before being dispatched.) This commit prints all discarded messages in the debug log, producing lines like: [1234567.890] discarded [unknown]@42.[event 0](0 fd, 12 byte) [1234567.890] discarded wl_callback@3.done(34567) [1234567.890] discarded [zombie]@13.[event 1](3 fd, 8 byte) The first indicates an event to an object that does not exist; the second, an event to an object that was deleted after decoding, but before dispatch; the third, an event to an object that left a 'zombie' marker behind to indicate which events have associated file descriptors. Signed-off-by: Manuel Stoeckl --- src/connection.c | 6 ++++-- src/wayland-client.c | 28 +++++++++++++++++++++++----- src/wayland-private.h | 2 +- src/wayland-server.c | 2 +- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/connection.c b/src/connection.c index ccbb9721..91d00c5d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1263,7 +1263,8 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) } void -wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send) +wl_closure_print(struct wl_closure *closure, struct wl_object *target, + int send, int discarded) { int i; struct argument_details arg; @@ -1274,8 +1275,9 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send) clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(stderr, "[%10.3f] %s%s@%u.%s(", + fprintf(stderr, "[%10.3f] %s%s%s@%u.%s(", time / 1000.0, + discarded ? "discarded " : "", send ? " -> " : "", target->interface->name, target->id, closure->message->name); diff --git a/src/wayland-client.c b/src/wayland-client.c index 58531eb0..3bf659c3 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -752,7 +752,7 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, } if (debug_client) - wl_closure_print(closure, &proxy->object, true); + wl_closure_print(closure, &proxy->object, true, false); if (wl_closure_send(closure, proxy->display->connection)) { wl_log("Error sending request: %s\n", strerror(errno)); @@ -1358,6 +1358,9 @@ queue_event(struct wl_display *display, int len) struct wl_closure *closure; const struct wl_message *message; struct wl_event_queue *queue; + struct timespec tp; + unsigned int time; + int num_zombie_fds; wl_connection_copy(display->connection, p, sizeof p); id = p[0]; @@ -1371,10 +1374,23 @@ queue_event(struct wl_display *display, int len) proxy = wl_map_lookup(&display->objects, id); if (!proxy || wl_object_is_zombie(&display->objects, id)) { struct wl_zombie *zombie = wl_map_lookup(&display->objects, id); + num_zombie_fds = (zombie && opcode < zombie->event_count) ? + zombie->fd_count[opcode] : 0; - if (zombie && zombie->fd_count[opcode]) + if (debug_client) { + clock_gettime(CLOCK_REALTIME, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + fprintf(stderr, "[%10.3f] discarded [%s]@%d.[event %d]" + "(%d fd, %d byte)\n", + time / 1000.0, + zombie ? "zombie" : "unknown", + id, opcode, + num_zombie_fds, size); + } + if (num_zombie_fds > 0) wl_connection_close_fds_in(display->connection, - zombie->fd_count[opcode]); + num_zombie_fds); wl_connection_consume(display->connection, size); return size; @@ -1433,6 +1449,8 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); if (proxy_destroyed) { + if (debug_client) + wl_closure_print(closure, &proxy->object, false, true); destroy_queued_closure(closure); return; } @@ -1441,13 +1459,13 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) if (proxy->dispatcher) { if (debug_client) - wl_closure_print(closure, &proxy->object, false); + wl_closure_print(closure, &proxy->object, false, false); wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { if (debug_client) - wl_closure_print(closure, &proxy->object, false); + wl_closure_print(closure, &proxy->object, false, false); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); diff --git a/src/wayland-private.h b/src/wayland-private.h index 9bf8cb75..493e1bee 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -211,7 +211,7 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); void wl_closure_print(struct wl_closure *closure, - struct wl_object *target, int send); + struct wl_object *target, int send, int discarded); void wl_closure_destroy(struct wl_closure *closure); diff --git a/src/wayland-server.c b/src/wayland-server.c index 0120326e..db734eea 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -150,7 +150,7 @@ log_closure(struct wl_resource *resource, struct wl_protocol_logger_message message; if (debug_server) - wl_closure_print(closure, object, send); + wl_closure_print(closure, object, send, false); if (!wl_list_empty(&display->protocol_loggers)) { message.resource = resource; From 80164ef3005e8bb5f785082b97a75cab15444f82 Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Fri, 9 Jul 2021 17:52:01 +1000 Subject: [PATCH 0730/1152] util: Avoid undefined behaviour in for_each_helper for_each_helper tries to calculate a one-past-the-end pointer for its wl_array input. This is fine when the array has one or more entries, but we initialize arrays by setting wl_array.data to NULL. Pointer arithmetic is only defined when both the pointer operand and the result point to the same allocation, or one-past-the-end of that allocation. As NULL points to no allocation, no pointer arithmetic can be performed on it, not even adding 0, even if the result is never dereferenced. This is caught by clang's ubsan from version 10. Many tests already hit this case, but I added an explicit test for iterating over an empty wl_map. Signed-off-by: Fergus Dall --- src/wayland-util.c | 15 +++++++++------ tests/map-test.c | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 47d0baed..c89a67bd 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -363,18 +363,21 @@ wl_map_lookup_flags(struct wl_map *map, uint32_t i) static enum wl_iterator_result for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) { - union map_entry *start, *end, *p; enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; + union map_entry entry, *start; + size_t count; - start = entries->data; - end = (union map_entry *) ((char *) entries->data + entries->size); + start = (union map_entry *) entries->data; + count = entries->size / sizeof(union map_entry); - for (p = start; p < end; p++) - if (p->data && !map_entry_is_free(*p)) { - ret = func(map_entry_get_data(*p), data, map_entry_get_flags(*p)); + for (size_t idx = 0; idx < count; idx++) { + entry = start[idx]; + if (entry.data && !map_entry_is_free(entry)) { + ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry)); if (ret != WL_ITERATOR_CONTINUE) break; } + } return ret; } diff --git a/tests/map-test.c b/tests/map-test.c index 8ecc1aa5..03568ea7 100644 --- a/tests/map-test.c +++ b/tests/map-test.c @@ -119,3 +119,19 @@ TEST(map_flags) wl_map_release(&map); } + +static enum wl_iterator_result never_run(void *element, void *data, uint32_t flags) +{ + assert(0); +} + +TEST(map_iter_empty) +{ + struct wl_map map; + + wl_map_init(&map, WL_MAP_SERVER_SIDE); + + wl_map_for_each(&map, never_run, NULL); + + wl_map_release(&map); +} From f6b78b76b2665598d495d3fe08dc34515405caa4 Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Fri, 9 Jul 2021 18:04:27 +1000 Subject: [PATCH 0731/1152] server: Fix undefined behavior in wl_socket_init_for_display_name This function constructs a socket path in sun_path using snprintf, which returns the amount of space that would have been used if the buffer was large enough. It then checks if this is larger then the actual buffer size and, if so, returns ENAMETOOLONG. This is correct. However, after calling snprintf and before checking that the length isn't too long, it tries to compute a pointer to the part of the path that matches the input name. It does this by adding the computed path length to the pointer to the start of the path buffer, which will take it to one-past the null terminator, and then walking backwards. If the path fits in the buffer, this will take it at most one-past-the-end of the allocation, which is allowed, but if the path is longer then the buffer then the pointer addition is undefined behavior. Fix this by moving the display name computation past the check that the path length is not too long. This is detected by the test socket_path_overflow_server_create under ubsan. Signed-off-by: Fergus Dall --- src/wayland-server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index db734eea..4783ab3e 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1514,8 +1514,6 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name) name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path, "%s%s%s", runtime_dir, separator, name) + 1; - s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name); - assert(name_size > 0); if (name_size > (int)sizeof s->addr.sun_path) { wl_log("error: socket path \"%s%s%s\" plus null terminator" @@ -1527,6 +1525,8 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name) return -1; } + s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name); + return 0; } From e5c3ac9bcd84df0f6bfd8fa1a1f549cab34eb439 Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Sat, 10 Jul 2021 00:09:59 +1000 Subject: [PATCH 0732/1152] connection-test: Pad out strings with null bytes The connection_demarshal test writes a 10 byte string into a wayland message, but doesn't pad it out to a four byte boundary. This leads to the last 32-bit word of the message being partially uninitialized, which triggers an msan violation when the message is written to the socket. Signed-off-by: Fergus Dall --- tests/connection-test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/connection-test.c b/tests/connection-test.c index 7220d875..eea92873 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -431,6 +431,7 @@ TEST(connection_demarshal) msg[0] = 400200; msg[1] = 24 << 16; msg[2] = 10; + msg[3 + msg[2]/4] = 0; memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "s", msg, (void *) validate_demarshal_s); @@ -438,6 +439,7 @@ TEST(connection_demarshal) msg[0] = 400200; msg[1] = 24 << 16; msg[2] = 10; + msg[3 + msg[2]/4] = 0; memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "?s", msg, (void *) validate_demarshal_s); From 91d98b622f2942221dfe0d7897801a2b0824b825 Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Sat, 10 Jul 2021 00:13:35 +1000 Subject: [PATCH 0733/1152] os-wrappers-test: Make syscall intercepts work with sanitizers Sanitizers need to intercept syscalls in the compiler run-time library, as do these tests. We try to make this work by using dlsym(RTLD_NEXT) to find the next definition in the chain, but here this approach won't work because the compiler run-time library is linked into the same elf object as the test interceptors are. The sanitizer library supports this by giving the intercept functions a prefix and making them only weakly alias the real names, so our interceptors can call the sanitizers interceptors explicitly, which will then use dlsym to call the real function. By making our declarations of the sanitizer interceptor function weak we can handle any combination of intercepts (including none, if there is no sanitizer). If our declaration is resolves to a NULL pointer, we just use dlsym. Signed-off-by: Fergus Dall --- tests/os-wrappers-test.c | 42 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 4d5de31b..0fd7853d 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -46,26 +46,44 @@ static int fall_back; -static int (*real_socket)(int, int, int); -static int wrapped_calls_socket; +/* Play nice with sanitizers + * + * Sanitizers need to intercept syscalls in the compiler run-time library. As + * this isn't a separate ELF object, the usual dlsym(RTLD_NEXT) approach won't + * work: there can only be one function named "socket" etc. To support this, the + * sanitizer library names its interceptors with the prefix __interceptor_ ("__" + * being reserved for the implementation) and then weakly aliases it to the real + * function. The functions we define below will override the weak alias, and we + * can call them by the __interceptor_ name directly. This allows the sanitizer + * to do its work before calling the next version of the function via dlsym. + * + * However! We also don't know which of these functions the sanitizer actually + * wants to override, so we have to declare our own weak symbols for + * __interceptor_ and check at run time if they linked to anything or not. +*/ -static int (*real_fcntl)(int, int, ...); -static int wrapped_calls_fcntl; +#define DECL(ret_type, func, ...) \ + ret_type __interceptor_ ## func(__VA_ARGS__) __attribute__((weak)); \ + static ret_type (*real_ ## func)(__VA_ARGS__); \ + static int wrapped_calls_ ## func; -static ssize_t (*real_recvmsg)(int, struct msghdr *, int); -static int wrapped_calls_recvmsg; +#define REAL(func) (__interceptor_ ## func) ? \ + __interceptor_ ## func : \ + (typeof(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func) -static int (*real_epoll_create1)(int); -static int wrapped_calls_epoll_create1; +DECL(int, socket, int, int, int); +DECL(int, fcntl, int, int, ...); +DECL(ssize_t, recvmsg, int, struct msghdr *, int); +DECL(int, epoll_create1, int); static void init_fallbacks(int do_fallbacks) { fall_back = do_fallbacks; - real_socket = dlsym(RTLD_NEXT, "socket"); - real_fcntl = dlsym(RTLD_NEXT, "fcntl"); - real_recvmsg = dlsym(RTLD_NEXT, "recvmsg"); - real_epoll_create1 = dlsym(RTLD_NEXT, "epoll_create1"); + real_socket = REAL(socket); + real_fcntl = REAL(fcntl); + real_recvmsg = REAL(recvmsg); + real_epoll_create1 = REAL(epoll_create1); } __attribute__ ((visibility("default"))) int From 2f05ceeb4de665c306d01a295b7f30659f8cae96 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sun, 17 Jan 2021 18:02:50 -0500 Subject: [PATCH 0734/1152] connection, client: Avoid locale-dependent float printing Specifically, in the log formed when WAYLAND_DEBUG is set, this commit ensures that floating point numbers are formatted using '.' instead of the locale-specific decimal separator. As the debug logs are not otherwise localized for end-users, and may be parsed by scripts, it is better to have consistent output here. The 24.8 fixed point numbers are now represented with 8 digits after the decimal, since this is both exact and simpler to compute. Signed-off-by: Manuel Stoeckl --- src/connection.c | 17 +++++++++++++---- src/wayland-client.c | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/connection.c b/src/connection.c index 91d00c5d..fc2c7c2e 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1275,8 +1275,8 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(stderr, "[%10.3f] %s%s%s@%u.%s(", - time / 1000.0, + fprintf(stderr, "[%7u.%03u] %s%s%s@%u.%s(", + time / 1000, time % 1000, discarded ? "discarded " : "", send ? " -> " : "", target->interface->name, target->id, @@ -1295,8 +1295,17 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, fprintf(stderr, "%d", closure->args[i].i); break; case 'f': - fprintf(stderr, "%f", - wl_fixed_to_double(closure->args[i].f)); + /* The magic number 390625 is 1e8 / 256 */ + if (closure->args[i].f >= 0) { + fprintf(stderr, "%d.%08d", + closure->args[i].f / 256, + 390625 * (closure->args[i].f % 256)); + } else { + + fprintf(stderr, "-%d.%08d", + closure->args[i].f / -256, + -390625 * (closure->args[i].f % 256)); + } break; case 's': if (closure->args[i].s) diff --git a/src/wayland-client.c b/src/wayland-client.c index 3bf659c3..34814d4e 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1381,9 +1381,9 @@ queue_event(struct wl_display *display, int len) clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(stderr, "[%10.3f] discarded [%s]@%d.[event %d]" + fprintf(stderr, "[%7u.%03u] discarded [%s]@%d.[event %d]" "(%d fd, %d byte)\n", - time / 1000.0, + time / 1000, time % 1000, zombie ? "zombie" : "unknown", id, opcode, num_zombie_fds, size); From 2aa0a83d36963c88ae98613b5b6120759cd50f8d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 May 2020 23:47:29 +0200 Subject: [PATCH 0735/1152] connection: print array size This makes it easier to understand how an xdg_toplevel is configured for instance. Signed-off-by: Simon Ser --- src/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index fc2c7c2e..1210772d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1332,7 +1332,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, fprintf(stderr, "nil"); break; case 'a': - fprintf(stderr, "array"); + fprintf(stderr, "array[%zu]", closure->args[i].a->size); break; case 'h': fprintf(stderr, "fd %d", closure->args[i].h); From 7940bbb7359654a424df9df06d014ee96a6cd8d8 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 20:56:51 +0100 Subject: [PATCH 0736/1152] ci: Add comments, rename build stages No non-cosmetic changes, just making things more accessible. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 63 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1fadda90..13bb030b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,47 @@ -.templates_sha: &template_sha 290b79e0e78eab67a83766f4e9691be554fc4afd # see https://docs.gitlab.com/ee/ci/yaml/#includefile +# This file uses the freedesktop ci-templates to build Weston and run our +# tests in CI. +# +# ci-templates uses a multi-stage build process. First, the base container +# image is built which contains the core distribution, the toolchain, and +# all our build dependencies. This container is aggressively cached; if a +# container image matching $FDO_DISTRIBUTION_TAG is found in either the +# upstream repo (wayland/weston) or the user's downstream repo, it is +# reused for the build. This gives us predictability of build and far +# quicker runtimes, however it means that any changes to the base container +# must also change $FDO_DISTRIBUTION_TAG. When changing this, please use +# the current date as well as a unique build identifier. +# +# After the container is either rebuilt (tag mismatch) or reused (tag +# previously used), the build stage executes within this container. +# +# The final stage is used to expose documentation and coverage information, +# including publishing documentation to the public site when built on the +# main branch. +# +# Apart from the 'variables', 'include', and 'stages' top-level anchors, +# everything not beginning with a dot ('.') is the name of a job which will +# be executed as part of CI, unless the rules specify that it should not be +# run. +# +# Variables prefixed with CI_ are generally provided by GitLab itself; +# variables prefixed with FDO_ and templates prefixed by .fdo are provided +# by the ci-templates. +# +# For more information on GitLab CI, including the YAML syntax, see: +# https://docs.gitlab.com/ee/ci/yaml/README.html +# +# Note that freedesktop.org uses the 'Community Edition' of GitLab, so features +# marked as 'premium' or 'ultimate' are not available to us. +# +# For more information on ci-templates, see: +# - documentation at https://freedesktop.pages.freedesktop.org/ci-templates/ +# - repo at https://gitlab.freedesktop.org/freedesktop/ci-templates/ +# Here we use a fixed ref in order to isolate ourselves from ci-templates +# API changes. If you need new features from ci-templates you must bump +# this to the current SHA you require from the ci-templates repo, however +# be aware that you may need to account for API changes when doing so. +.templates_sha: &template_sha 290b79e0e78eab67a83766f4e9691be554fc4afd # see https://docs.gitlab.com/ee/ci/yaml/#includefile include: # Debian container builder template @@ -12,12 +54,15 @@ include: file: '/templates/ci-fairy.yml' +# Define the build stages. These are used for UI grouping as well as +# dependencies. stages: - - review - - prep - - build + - "Merge request checks" + - "Base container" + - "Build and test" +# Base variables used for anything using a Debian environment variables: DEBIAN_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' DEBIAN_EXEC: 'pip3 install meson==0.52.1' @@ -40,7 +85,7 @@ variables: check-commit: extends: - .fdo.ci-fairy - stage: review + stage: "Merge request checks" script: - ci-fairy check-commits --signed-off-by --junit-xml=results.xml variables: @@ -50,20 +95,24 @@ check-commit: junit: results.xml +# Build our base container image, which contains the core distribution, the +# toolchain, and all our build dependencies. This will be reused in the build +# stage. debian:buster@container-prep: extends: - .debian.buster - .fdo.container-build@debian - stage: prep + stage: "Base container" variables: GIT_STRATEGY: none +# Full build and test. build-native: extends: - .debian.buster - .fdo.distribution-image@debian - stage: build + stage: "Build and test" script: - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" - export PREFIX="$(pwd)/prefix-$BUILD_ID" From b88e1d40b093df2a244bd60b29b43f307ff3af27 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:06:11 +0100 Subject: [PATCH 0737/1152] ci: Parameterise and template build This will make it a lot easier to add other variants later. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 74 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13bb030b..d5a94e4c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,6 +53,13 @@ include: ref: *template_sha file: '/templates/ci-fairy.yml' +variables: + FDO_UPSTREAM_REPO: wayland/wayland + FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH" + # bump this tag every time you change something which requires rebuilding the + # base image + FDO_DISTRIBUTION_TAG: "2021-08-03.0" + # Define the build stages. These are used for UI grouping as well as # dependencies. @@ -63,23 +70,18 @@ stages: # Base variables used for anything using a Debian environment -variables: - DEBIAN_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' - DEBIAN_EXEC: 'pip3 install meson==0.52.1' - # these tags should be updated each time the list of packages is updated - # changing these will force rebuilding the associated image - # Note: these tags have no meaning and are not tied to a particular - # wayland version - DEBIAN_TAG: '2020-12-14.0' - FDO_UPSTREAM_REPO: wayland/wayland - - -.debian.buster: +.os-debian: variables: - FDO_DISTRIBUTION_PACKAGES: $DEBIAN_PACKAGES - FDO_DISTRIBUTION_TAG: $DEBIAN_TAG - FDO_DISTRIBUTION_VERSION: 'buster' - FDO_DISTRIBUTION_EXEC: $DEBIAN_EXEC + BUILD_OS: debian + FDO_DISTRIBUTION_VERSION: buster + FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' + FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.52.1' + +.debian-x86_64: + extends: + - .os-debian + variables: + BUILD_ARCH: "x86-64" check-commit: @@ -98,26 +100,39 @@ check-commit: # Build our base container image, which contains the core distribution, the # toolchain, and all our build dependencies. This will be reused in the build # stage. -debian:buster@container-prep: +x86_64-debian-container_prep: extends: - - .debian.buster + - .debian-x86_64 - .fdo.container-build@debian stage: "Base container" variables: GIT_STRATEGY: none -# Full build and test. -build-native: +# Core build environment. +.build-env: + before_script: + - export BUILD_ID="wayland-$CI_JOB_NAME-$CI_COMMIT_SHA-$CI_JOB_ID" + - export PREFIX="$(pwd)/prefix-$BUILD_ID" + - export BUILDDIR="$(pwd)/build-$BUILD_ID" + - mkdir "$BUILDDIR" "$PREFIX" + + +# OS/architecture-specific variants +.build-env-debian-x86_64: extends: - - .debian.buster - - .fdo.distribution-image@debian + - .fdo.suffixed-image@debian + - .debian-x86_64 + - .build-env + needs: + - job: x86_64-debian-container_prep + artifacts: false + + +# Full build and test. +.do-build: stage: "Build and test" script: - - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" - - export PREFIX="$(pwd)/prefix-$BUILD_ID" - - export BUILDDIR="$(pwd)/build-$BUILD_ID" - - mkdir "$BUILDDIR" "$PREFIX" - cd "$BUILDDIR" - meson --prefix="$PREFIX" -Db_sanitize=address,undefined -Dicon_directory=/usr/share/X11/icons .. - ninja -k0 test @@ -128,3 +143,10 @@ build-native: paths: - build-meson/meson-logs - prefix-* + + +# Full build and test. +x86_64-debian-build: + extends: + - .build-env-debian-x86_64 + - .do-build From 33767673bc2e87472aa6e969925ea3643dd52a27 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:08:01 +0100 Subject: [PATCH 0738/1152] ci: Add AArch64 build Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d5a94e4c..0d6e3f6c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,6 +83,12 @@ stages: variables: BUILD_ARCH: "x86-64" +.debian-aarch64: + extends: + - .os-debian + variables: + BUILD_ARCH: "aarch64" + check-commit: extends: @@ -108,6 +114,16 @@ x86_64-debian-container_prep: variables: GIT_STRATEGY: none +aarch64-debian-container_prep: + extends: + - .debian-aarch64 + - .fdo.container-build@debian + tags: + - aarch64 + stage: "Base container" + variables: + GIT_STRATEGY: none + # Core build environment. .build-env: @@ -128,6 +144,24 @@ x86_64-debian-container_prep: - job: x86_64-debian-container_prep artifacts: false +.build-env-debian-aarch64: + extends: + - .fdo.suffixed-image@debian + - .debian-aarch64 + - .build-env + variables: + # At least with the versions we have, the LSan runtime makes fork unusably + # slow on AArch64, which is bad news since the test suite decides to fork + # for every single subtest. For now, in order to get AArch64 builds and + # tests into CI, just assume that we're not going to leak any more on + # AArch64 than we would on ARMv7 or x86-64. + ASAN_OPTIONS: "detect_leaks=0" + tags: + - aarch64 + needs: + - job: aarch64-debian-container_prep + artifacts: false + # Full build and test. .do-build: @@ -150,3 +184,8 @@ x86_64-debian-build: extends: - .build-env-debian-x86_64 - .do-build + +aarch64-debian-build: + extends: + - .build-env-debian-aarch64 + - .do-build From c4865c774bdbb5f1f7fc59158103c307cf8cdbc2 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:09:50 +0100 Subject: [PATCH 0739/1152] ci: Add ARMv7 build Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d6e3f6c..73f76189 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -89,6 +89,12 @@ stages: variables: BUILD_ARCH: "aarch64" +.debian-armv7: + extends: + - .os-debian + variables: + BUILD_ARCH: "armv7" + check-commit: extends: @@ -124,6 +130,17 @@ aarch64-debian-container_prep: variables: GIT_STRATEGY: none +armv7-debian-container_prep: + extends: + - .debian-armv7 + - .fdo.container-build@debian + tags: + - aarch64 + stage: "Base container" + variables: + GIT_STRATEGY: none + FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION" + # Core build environment. .build-env: @@ -162,6 +179,17 @@ aarch64-debian-container_prep: - job: aarch64-debian-container_prep artifacts: false +.build-env-debian-armv7: + extends: + - .fdo.suffixed-image@debian + - .debian-armv7 + - .build-env + tags: + - aarch64 + needs: + - job: armv7-debian-container_prep + artifacts: false + # Full build and test. .do-build: @@ -189,3 +217,8 @@ aarch64-debian-build: extends: - .build-env-debian-aarch64 - .do-build + +armv7-debian-build: + extends: + - .build-env-debian-armv7 + - .do-build From e4deb4dc66560cf17e85745fe8aa0e35bfa4f4b3 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:13:25 +0100 Subject: [PATCH 0740/1152] ci: Only run ci-fairy on MRs This requires adding rules to all the jobs, as it's all or nothing. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 73f76189..7e356394 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -68,6 +68,9 @@ stages: - "Base container" - "Build and test" +.ci-rules: + rules: + - when: on_success # Base variables used for anything using a Debian environment .os-debian: @@ -96,10 +99,15 @@ stages: BUILD_ARCH: "armv7" +# Does not inherit .ci-rules as we only want it to run in MR context. check-commit: extends: - .fdo.ci-fairy stage: "Merge request checks" + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + when: always + - when: never script: - ci-fairy check-commits --signed-off-by --junit-xml=results.xml variables: @@ -114,6 +122,7 @@ check-commit: # stage. x86_64-debian-container_prep: extends: + - .ci-rules - .debian-x86_64 - .fdo.container-build@debian stage: "Base container" @@ -122,6 +131,7 @@ x86_64-debian-container_prep: aarch64-debian-container_prep: extends: + - .ci-rules - .debian-aarch64 - .fdo.container-build@debian tags: @@ -132,6 +142,7 @@ aarch64-debian-container_prep: armv7-debian-container_prep: extends: + - .ci-rules - .debian-armv7 - .fdo.container-build@debian tags: @@ -193,6 +204,8 @@ armv7-debian-container_prep: # Full build and test. .do-build: + extends: + - .ci-rules stage: "Build and test" script: - cd "$BUILDDIR" From 705154a09d599b2debe09e90f51e2e332e6bb930 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:14:04 +0100 Subject: [PATCH 0741/1152] ci: Use consistent YAML indendation Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7e356394..50c3244c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -205,19 +205,19 @@ armv7-debian-container_prep: # Full build and test. .do-build: extends: - - .ci-rules + - .ci-rules stage: "Build and test" script: - - cd "$BUILDDIR" - - meson --prefix="$PREFIX" -Db_sanitize=address,undefined -Dicon_directory=/usr/share/X11/icons .. - - ninja -k0 test - - ninja clean + - cd "$BUILDDIR" + - meson --prefix="$PREFIX" -Db_sanitize=address,undefined -Dicon_directory=/usr/share/X11/icons .. + - ninja -k0 test + - ninja clean artifacts: name: wayland-meson-$CI_COMMIT_SHA-$CI_JOB_ID when: always paths: - - build-meson/meson-logs - - prefix-* + - build-meson/meson-logs + - prefix-* # Full build and test. From 71ff5fe0af035512f54cf9b20a023467fef4541c Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:31:36 +0100 Subject: [PATCH 0742/1152] ci: Add release builds Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 50c3244c..4fe9791b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -67,6 +67,7 @@ stages: - "Merge request checks" - "Base container" - "Build and test" + - "Other build configurations" .ci-rules: rules: @@ -155,6 +156,8 @@ armv7-debian-container_prep: # Core build environment. .build-env: + variables: + MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined" before_script: - export BUILD_ID="wayland-$CI_JOB_NAME-$CI_COMMIT_SHA-$CI_JOB_ID" - export PREFIX="$(pwd)/prefix-$BUILD_ID" @@ -162,6 +165,13 @@ armv7-debian-container_prep: - mkdir "$BUILDDIR" "$PREFIX" +# Build variants to be stacked on as required. +.build-release: + stage: "Other build configurations" + variables: + MESON_BUILD_TYPE: "-Dbuildtype=release" + + # OS/architecture-specific variants .build-env-debian-x86_64: extends: @@ -209,7 +219,7 @@ armv7-debian-container_prep: stage: "Build and test" script: - cd "$BUILDDIR" - - meson --prefix="$PREFIX" -Db_sanitize=address,undefined -Dicon_directory=/usr/share/X11/icons .. + - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons ${MESON_BUILD_TYPE} .. - ninja -k0 test - ninja clean artifacts: @@ -226,12 +236,30 @@ x86_64-debian-build: - .build-env-debian-x86_64 - .do-build +x86_64-release-debian-build: + extends: + - .build-env-debian-x86_64 + - .do-build + - .build-release + aarch64-debian-build: extends: - .build-env-debian-aarch64 - .do-build +aarch64-release-debian-build: + extends: + - .build-env-debian-aarch64 + - .do-build + - .build-release + armv7-debian-build: extends: - .build-env-debian-armv7 - .do-build + +armv7-release-debian-build: + extends: + - .build-env-debian-armv7 + - .do-build + - .build-release From 0d3e47abdc75697d463d69a1be8d0449fc2cb4a7 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:33:03 +0100 Subject: [PATCH 0743/1152] ci: Use appropriate concurrency level The appropriate concurrency level is not necessarily the number of available CPUs; limit it to what the runners tell us we should be using. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4fe9791b..c5c76856 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -220,7 +220,8 @@ armv7-debian-container_prep: script: - cd "$BUILDDIR" - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons ${MESON_BUILD_TYPE} .. - - ninja -k0 test + - ninja -k0 -j${FDO_CI_CONCURRENT:-4} + - meson test --num-processes ${FDO_CI_CONCURRENT:-4} - ninja clean artifacts: name: wayland-meson-$CI_COMMIT_SHA-$CI_JOB_ID From 7769b63141ee5ebbc0f8ca7af84d6503487de26b Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:32:02 +0100 Subject: [PATCH 0744/1152] ci: Use Werror No point warning on stuff if we don't make it fail. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c5c76856..cfec9334 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -219,7 +219,7 @@ armv7-debian-container_prep: stage: "Build and test" script: - cd "$BUILDDIR" - - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons ${MESON_BUILD_TYPE} .. + - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons -Dwerror=true ${MESON_BUILD_TYPE} .. - ninja -k0 -j${FDO_CI_CONCURRENT:-4} - meson test --num-processes ${FDO_CI_CONCURRENT:-4} - ninja clean From c4453ce1a517c3b6fa2a1fb6cce8b3398e88e9ec Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 3 Aug 2021 21:53:12 +0100 Subject: [PATCH 0745/1152] ci: Sanitise build and install paths No sense in generating enormously long paths. This also happens to fix artifacts not actually recording anything because we had a mismatch in artifact paths vs. actual paths. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cfec9334..c8fdf090 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -159,9 +159,9 @@ armv7-debian-container_prep: variables: MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined" before_script: - - export BUILD_ID="wayland-$CI_JOB_NAME-$CI_COMMIT_SHA-$CI_JOB_ID" - - export PREFIX="$(pwd)/prefix-$BUILD_ID" - - export BUILDDIR="$(pwd)/build-$BUILD_ID" + - export BUILD_ID="wayland-$CI_JOB_NAME" + - export PREFIX="${CI_PROJECT_DIR}/prefix-${BUILD_ID}" + - export BUILDDIR="${CI_PROJECT_DIR}/build-${BUILD_ID}" - mkdir "$BUILDDIR" "$PREFIX" @@ -224,10 +224,10 @@ armv7-debian-container_prep: - meson test --num-processes ${FDO_CI_CONCURRENT:-4} - ninja clean artifacts: - name: wayland-meson-$CI_COMMIT_SHA-$CI_JOB_ID + name: wayland-$CI_JOB_NAME when: always paths: - - build-meson/meson-logs + - build-*/meson-logs - prefix-* From f80879c03c194109190f48eb49a5ed649ce5da97 Mon Sep 17 00:00:00 2001 From: Olivier Tilloy Date: Wed, 5 May 2021 17:15:33 +0200 Subject: [PATCH 0746/1152] cursor: Try to fall back to a default xcursor theme first The use case is systems where for some reason the current xcursor theme cannot be accessed (an application packaged as a strictly confined snap, for example). Before falling back to wayland's default cursor theme, it is worth trying the xcursor theme called "default", which hopefully looks better than the former. Fixes: https://gitlab.gnome.org/Community/Ubuntu/gnome-sdk/-/issues/6 Signed-off-by: Olivier Tilloy --- cursor/wayland-cursor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 7da70141..dd48e21e 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -404,6 +404,9 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) xcursor_load_theme(name, size, load_callback, theme); + if (theme->cursor_count == 0) + xcursor_load_theme(NULL, size, load_callback, theme); + if (theme->cursor_count == 0) load_default_theme(theme); From 2dfa0dcb24766b03f4a9f05154b474b722aaa025 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 Aug 2021 17:24:02 +0200 Subject: [PATCH 0747/1152] cursor: rename load_default_theme to load_fallback_theme The theme getting loaded by this function is not to be confused with the theme named "default" located on the filesystem. Instead, it's a minimal theme directly bundled into libwayland-cursor. Make this clearer by naming this theme "fallback". Signed-off-by: Simon Ser --- cursor/wayland-cursor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index dd48e21e..55c62eeb 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -252,7 +252,7 @@ err_free_cursor: } static void -load_default_theme(struct wl_cursor_theme *theme) +load_fallback_theme(struct wl_cursor_theme *theme) { uint32_t i; @@ -408,7 +408,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) xcursor_load_theme(NULL, size, load_callback, theme); if (theme->cursor_count == 0) - load_default_theme(theme); + load_fallback_theme(theme); return theme; From 6ebe3cfed0aaa934cd571d2b89c0ba23aa242055 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 Aug 2021 18:09:53 +0200 Subject: [PATCH 0748/1152] cursor: remove unused wl_cursor_theme.name Let's just delete this field since it's not used anywhere and not exposed in our public API. Signed-off-by: Simon Ser --- cursor/wayland-cursor.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 55c62eeb..b3495e0c 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -129,7 +129,6 @@ struct wl_cursor_theme { struct wl_cursor **cursors; struct wl_shm *shm; struct shm_pool *pool; - char *name; int size; }; @@ -256,9 +255,6 @@ load_fallback_theme(struct wl_cursor_theme *theme) { uint32_t i; - free(theme->name); - theme->name = strdup("default"); - theme->cursor_count = ARRAY_LENGTH(cursor_metadata); theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors)); @@ -391,9 +387,6 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) if (!name) name = "default"; - theme->name = strdup(name); - if (!theme->name) - goto out_error_name; theme->size = size; theme->cursor_count = 0; theme->cursors = NULL; @@ -413,8 +406,6 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) return theme; out_error_pool: - free(theme->name); -out_error_name: free(theme); return NULL; } @@ -433,7 +424,6 @@ wl_cursor_theme_destroy(struct wl_cursor_theme *theme) shm_pool_destroy(theme->pool); - free(theme->name); free(theme->cursors); free(theme); } From 942f1d88431d394ac661af7b192154ba7aa68c29 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 21 Jul 2021 16:03:12 -0500 Subject: [PATCH 0749/1152] client: Refactor wl_proxy_destroy critical section Split wl_proxy_destroy into two pieces, wl_proxy_destroy_unlocked which performs the critical section code with no locking, and wl_proxy_destroy which locks before calling that. We'll use the new unlocked variant later in code that already holds the lock. There is a slight functional change - an aborting check is now called with the lock held. This should be harmless as wl_abort() performs no locking. Signed-off-by: Derek Foreman --- src/wayland-client.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 34814d4e..d4c8cfa0 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -514,12 +514,26 @@ proxy_destroy(struct wl_proxy *proxy) wl_proxy_unref(proxy); } +static void +wl_proxy_destroy_caller_locks(struct wl_proxy *proxy) +{ + if (proxy->flags & WL_PROXY_FLAG_WRAPPER) + wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n"); + + proxy_destroy(proxy); +} + /** Destroy a proxy object * * \param proxy The proxy to be destroyed * * \c proxy must not be a proxy wrapper. * + * \note This function will abort in response to egregious + * errors, and will do so with the display lock held. This means + * SIGABRT handlers must not perform any actions that would + * attempt to take that lock, or a deadlock would occur. + * * \memberof wl_proxy */ WL_EXPORT void @@ -527,11 +541,10 @@ wl_proxy_destroy(struct wl_proxy *proxy) { struct wl_display *display = proxy->display; - if (proxy->flags & WL_PROXY_FLAG_WRAPPER) - wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n"); - pthread_mutex_lock(&display->mutex); - proxy_destroy(proxy); + + wl_proxy_destroy_caller_locks(proxy); + pthread_mutex_unlock(&display->mutex); } From 23e4a7060080ebb61f516a2edcd71ab123029c0e Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 21 Jul 2021 16:26:00 -0500 Subject: [PATCH 0750/1152] client: Add new proxy marshalling functions with flags There's a race when destroying wayland objects in a multi-threaded client. This occurs because we call: wl_proxy_marshal(foo); wl_proxy_destroy(foo); And each of these functions takes, and releases, the display mutex. Between the two calls, the display is not locked. In order to allow atomically marshalling the proxy and destroying the proxy without releasing the lock, add yet more wl_proxy_marshal_* functions. This time add flags and jam in all existing warts with the hope that we can make it future proof this time. Signed-off-by: Derek Foreman --- src/wayland-client-core.h | 18 ++++++++ src/wayland-client.c | 89 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 0cd96e01..ce91a6f6 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -119,9 +119,27 @@ struct wl_display; */ struct wl_event_queue; +/** Destroy proxy after marshalling + * @ingroup wl_proxy + */ +#define WL_MARSHAL_FLAG_DESTROY (1 << 0) + void wl_event_queue_destroy(struct wl_event_queue *queue); +struct wl_proxy * +wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, ...); + +struct wl_proxy * +wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args); + void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); diff --git a/src/wayland-client.c b/src/wayland-client.c index d4c8cfa0..63ce0d01 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -737,12 +737,94 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, union wl_argument *args, const struct wl_interface *interface, uint32_t version) +{ + return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, 0, args); +} + +/** Prepare a request to be sent to the compositor + * + * \param proxy The proxy object + * \param opcode Opcode of the request to be sent + * \param interface The interface to use for the new proxy + * \param version The protocol object version of the new proxy + * \param flags Flags that modify marshalling behaviour + * \param ... Extra arguments for the given request + * \return A new wl_proxy for the new_id argument or NULL on error + * + * Translates the request given by opcode and the extra arguments into the + * wire format and write it to the connection buffer. + * + * For new-id arguments, this function will allocate a new wl_proxy + * and send the ID to the server. The new wl_proxy will be returned + * on success or NULL on error with errno set accordingly. The newly + * created proxy will have the version specified. + * + * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy + * is destroyed atomically with the marshalling in order to prevent + * races that can occur if the display lock is dropped between the + * marshal and destroy operations. + * + * \note This should not normally be used by non-generated code. + * + * \memberof wl_proxy + */ +WL_EXPORT struct wl_proxy * +wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, uint32_t version, + uint32_t flags, ...) +{ + union wl_argument args[WL_CLOSURE_MAX_ARGS]; + va_list ap; + + va_start(ap, flags); + wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, + args, WL_CLOSURE_MAX_ARGS, ap); + va_end(ap); + + return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, flags, args); +} + +/** Prepare a request to be sent to the compositor + * + * \param proxy The proxy object + * \param opcode Opcode of the request to be sent + * \param interface The interface to use for the new proxy + * \param version The protocol object version for the new proxy + * \param flags Flags that modify marshalling behaviour + * \param args Extra arguments for the given request + * + * Translates the request given by opcode and the extra arguments into the + * wire format and write it to the connection buffer. This version takes an + * array of the union type wl_argument. + * + * For new-id arguments, this function will allocate a new wl_proxy + * and send the ID to the server. The new wl_proxy will be returned + * on success or NULL on error with errno set accordingly. The newly + * created proxy will have the version specified. + * + * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy + * is destroyed atomically with the marshalling in order to prevent + * races that can occur if the display lock is dropped between the + * marshal and destroy operations. + * + * \note This is intended to be used by language bindings and not in + * non-generated code. + * + * \sa wl_proxy_marshal_flags() + * + * \memberof wl_proxy + */ +WL_EXPORT struct wl_proxy * +wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, uint32_t version, + uint32_t flags, union wl_argument *args) { struct wl_closure *closure; struct wl_proxy *new_proxy = NULL; const struct wl_message *message; + struct wl_display *disp = proxy->display; - pthread_mutex_lock(&proxy->display->mutex); + pthread_mutex_lock(&disp->mutex); message = &proxy->object.interface->methods[opcode]; if (interface) { @@ -775,7 +857,10 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, wl_closure_destroy(closure); err_unlock: - pthread_mutex_unlock(&proxy->display->mutex); + if (flags & WL_MARSHAL_FLAG_DESTROY) + wl_proxy_destroy_caller_locks(proxy); + + pthread_mutex_unlock(&disp->mutex); return new_proxy; } From 0e0274af0c9f60d2759713df136f4294054c9096 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 21 Jul 2021 16:32:36 -0500 Subject: [PATCH 0751/1152] scanner: Use the new atomic marshal/destroy function Use the new flagged marshal+destroy function in generated code. It's intended as a replacement for all existing wl_proxy_marshal_* functions, so I've used it to replace them all. This results in a large update to the scanner test files as well. We now pass the new WL_MARSHAL_FLAG_DESTROY flag when appropriate, so the race condition in #86 caused by releasing the display mutex between marshalling the proxy and destroying the proxy is now gone. Fixes #86 Signed-off-by: Derek Foreman --- src/scanner.c | 63 ++++---- tests/data/example-client.h | 284 +++++++++++++++------------------ tests/data/small-client-core.h | 14 +- tests/data/small-client.h | 14 +- 4 files changed, 170 insertions(+), 205 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 64df6e8a..6a956036 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1238,38 +1238,40 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) printf(")\n" "{\n"); - if (ret && ret->interface_name == NULL) { - /* an arg has type ="new_id" but interface is not - * provided, such as in wl_registry.bind */ - printf("\tstruct wl_proxy *%s;\n\n" - "\t%s = wl_proxy_marshal_constructor_versioned(" - "(struct wl_proxy *) %s,\n" - "\t\t\t %s_%s, interface, version", - ret->name, ret->name, - interface->name, - interface->uppercase_name, - m->uppercase_name); - } else if (ret) { - /* Normal factory case, an arg has type="new_id" and - * an interface is provided */ - printf("\tstruct wl_proxy *%s;\n\n" - "\t%s = wl_proxy_marshal_constructor(" - "(struct wl_proxy *) %s,\n" - "\t\t\t %s_%s, &%s_interface", - ret->name, ret->name, - interface->name, - interface->uppercase_name, - m->uppercase_name, - ret->interface_name); + printf("\t"); + if (ret) { + printf("struct wl_proxy *%s;\n\n" + "\t%s = ", ret->name, ret->name); + } + printf("wl_proxy_marshal_flags(" + "(struct wl_proxy *) %s,\n" + "\t\t\t %s_%s", + interface->name, + interface->uppercase_name, + m->uppercase_name); + + if (ret) { + if (ret->interface_name) { + /* Normal factory case, an arg has type="new_id" and + * an interface is provided */ + printf(", &%s_interface", ret->interface_name); + } else { + /* an arg has type ="new_id" but interface is not + * provided, such as in wl_registry.bind */ + printf(", interface"); + } } else { /* No args have type="new_id" */ - printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n" - "\t\t\t %s_%s", - interface->name, - interface->uppercase_name, - m->uppercase_name); + printf(", NULL"); } + if (ret && ret->interface_name == NULL) + printf(", version"); + else + printf(", wl_proxy_get_version((struct wl_proxy *) %s)", + interface->name); + printf(", %s", m->destructor ? "WL_MARSHAL_FLAG_DESTROY" : "0"); + wl_list_for_each(a, &m->arg_list, link) { if (a->type == NEW_ID) { if (a->interface_name == NULL) @@ -1281,11 +1283,6 @@ emit_stubs(struct wl_list *message_list, struct interface *interface) } printf(");\n"); - if (m->destructor) - printf("\n\twl_proxy_destroy(" - "(struct wl_proxy *) %s);\n", - interface->name); - if (ret && ret->interface_name == NULL) printf("\n\treturn (void *) %s;\n", ret->name); else if (ret) diff --git a/tests/data/example-client.h b/tests/data/example-client.h index 9a2200a9..39d799c1 100644 --- a/tests/data/example-client.h +++ b/tests/data/example-client.h @@ -1011,8 +1011,8 @@ wl_display_sync(struct wl_display *wl_display) { struct wl_proxy *callback; - callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display, - WL_DISPLAY_SYNC, &wl_callback_interface, NULL); + callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, + WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); return (struct wl_callback *) callback; } @@ -1029,8 +1029,8 @@ wl_display_get_registry(struct wl_display *wl_display) { struct wl_proxy *registry; - registry = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display, - WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL); + registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, + WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); return (struct wl_registry *) registry; } @@ -1142,8 +1142,8 @@ wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl { struct wl_proxy *id; - id = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) wl_registry, - WL_REGISTRY_BIND, interface, version, name, interface->name, version, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry, + WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL); return (void *) id; } @@ -1258,8 +1258,8 @@ wl_compositor_create_surface(struct wl_compositor *wl_compositor) { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); return (struct wl_surface *) id; } @@ -1274,8 +1274,8 @@ wl_compositor_create_region(struct wl_compositor *wl_compositor) { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); return (struct wl_region *) id; } @@ -1338,8 +1338,8 @@ wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32 { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, NULL, offset, width, height, stride, format); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format); return (struct wl_buffer *) id; } @@ -1356,10 +1356,8 @@ wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32 static inline void wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) { - wl_proxy_marshal((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_shm_pool); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY); } /** @@ -1373,8 +1371,8 @@ wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) static inline void wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size) { - wl_proxy_marshal((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_RESIZE, size); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size); } #ifndef WL_SHM_ERROR_ENUM @@ -1734,8 +1732,8 @@ wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size) { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm, - WL_SHM_CREATE_POOL, &wl_shm_pool_interface, NULL, fd, size); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm, + WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size); return (struct wl_shm_pool *) id; } @@ -1819,10 +1817,8 @@ wl_buffer_get_version(struct wl_buffer *wl_buffer) static inline void wl_buffer_destroy(struct wl_buffer *wl_buffer) { - wl_proxy_marshal((struct wl_proxy *) wl_buffer, - WL_BUFFER_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_buffer); + wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer, + WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_DATA_OFFER_ERROR_ENUM @@ -2015,8 +2011,8 @@ wl_data_offer_get_version(struct wl_data_offer *wl_data_offer) static inline void wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type) { - wl_proxy_marshal((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_ACCEPT, serial, mime_type); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type); } /** @@ -2041,8 +2037,8 @@ wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const static inline void wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd) { - wl_proxy_marshal((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_RECEIVE, mime_type, fd); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd); } /** @@ -2053,10 +2049,8 @@ wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type static inline void wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) { - wl_proxy_marshal((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_data_offer); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY); } /** @@ -2077,8 +2071,8 @@ wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) static inline void wl_data_offer_finish(struct wl_data_offer *wl_data_offer) { - wl_proxy_marshal((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_FINISH); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0); } /** @@ -2119,8 +2113,8 @@ wl_data_offer_finish(struct wl_data_offer *wl_data_offer) static inline void wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action) { - wl_proxy_marshal((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_SET_ACTIONS, dnd_actions, preferred_action); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action); } #ifndef WL_DATA_SOURCE_ERROR_ENUM @@ -2344,8 +2338,8 @@ wl_data_source_get_version(struct wl_data_source *wl_data_source) static inline void wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type) { - wl_proxy_marshal((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_OFFER, mime_type); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type); } /** @@ -2356,10 +2350,8 @@ wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_typ static inline void wl_data_source_destroy(struct wl_data_source *wl_data_source) { - wl_proxy_marshal((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_data_source); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY); } /** @@ -2382,8 +2374,8 @@ wl_data_source_destroy(struct wl_data_source *wl_data_source) static inline void wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions) { - wl_proxy_marshal((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_SET_ACTIONS, dnd_actions); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions); } #ifndef WL_DATA_DEVICE_ERROR_ENUM @@ -2614,8 +2606,8 @@ wl_data_device_destroy(struct wl_data_device *wl_data_device) static inline void wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial) { - wl_proxy_marshal((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_START_DRAG, source, origin, icon, serial); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial); } /** @@ -2629,8 +2621,8 @@ wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_ static inline void wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial) { - wl_proxy_marshal((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_SET_SELECTION, source, serial); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial); } /** @@ -2641,10 +2633,8 @@ wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_da static inline void wl_data_device_release(struct wl_data_device *wl_data_device) { - wl_proxy_marshal((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_RELEASE); - - wl_proxy_destroy((struct wl_proxy *) wl_data_device); + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM @@ -2747,8 +2737,8 @@ wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager, - WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL); return (struct wl_data_source *) id; } @@ -2763,8 +2753,8 @@ wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_de { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager, - WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, NULL, seat); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat); return (struct wl_data_device *) id; } @@ -2828,8 +2818,8 @@ wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shell, - WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, NULL, surface); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell, + WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface); return (struct wl_shell_surface *) id; } @@ -3099,8 +3089,8 @@ wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface) static inline void wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_PONG, serial); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial); } /** @@ -3115,8 +3105,8 @@ wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial static inline void wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_MOVE, seat, serial); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial); } /** @@ -3131,8 +3121,8 @@ wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat static inline void wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_RESIZE, seat, serial, edges); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges); } /** @@ -3145,8 +3135,8 @@ wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_sea static inline void wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TOPLEVEL); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0); } /** @@ -3163,8 +3153,8 @@ wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) static inline void wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TRANSIENT, parent, x, y, flags); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags); } /** @@ -3207,8 +3197,8 @@ wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct static inline void wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_FULLSCREEN, method, framerate, output); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output); } /** @@ -3237,8 +3227,8 @@ wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint3 static inline void wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_POPUP, seat, serial, parent, x, y, flags); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags); } /** @@ -3266,8 +3256,8 @@ wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_ static inline void wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_MAXIMIZED, output); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output); } /** @@ -3284,8 +3274,8 @@ wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct static inline void wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TITLE, title); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title); } /** @@ -3301,8 +3291,8 @@ wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char static inline void wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_) { - wl_proxy_marshal((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_CLASS, class_); + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_); } #ifndef WL_SURFACE_ERROR_ENUM @@ -3457,10 +3447,8 @@ wl_surface_get_version(struct wl_surface *wl_surface) static inline void wl_surface_destroy(struct wl_surface *wl_surface) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_surface); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY); } /** @@ -3509,8 +3497,8 @@ wl_surface_destroy(struct wl_surface *wl_surface) static inline void wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_ATTACH, buffer, x, y); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y); } /** @@ -3541,8 +3529,8 @@ wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32 static inline void wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE, x, y, width, height); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); } /** @@ -3586,8 +3574,8 @@ wl_surface_frame(struct wl_surface *wl_surface) { struct wl_proxy *callback; - callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_surface, - WL_SURFACE_FRAME, &wl_callback_interface, NULL); + callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL); return (struct wl_callback *) callback; } @@ -3623,8 +3611,8 @@ wl_surface_frame(struct wl_surface *wl_surface) static inline void wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, region); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); } /** @@ -3656,8 +3644,8 @@ wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *re static inline void wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_INPUT_REGION, region); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); } /** @@ -3684,8 +3672,8 @@ wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *reg static inline void wl_surface_commit(struct wl_surface *wl_surface) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_COMMIT); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0); } /** @@ -3724,8 +3712,8 @@ wl_surface_commit(struct wl_surface *wl_surface) static inline void wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_BUFFER_TRANSFORM, transform); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform); } /** @@ -3758,8 +3746,8 @@ wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform static inline void wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_BUFFER_SCALE, scale); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale); } /** @@ -3801,8 +3789,8 @@ wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) static inline void wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) { - wl_proxy_marshal((struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE_BUFFER, x, y, width, height); + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); } #ifndef WL_SEAT_CAPABILITY_ENUM @@ -3967,8 +3955,8 @@ wl_seat_get_pointer(struct wl_seat *wl_seat) { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat, - WL_SEAT_GET_POINTER, &wl_pointer_interface, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); return (struct wl_pointer *) id; } @@ -3989,8 +3977,8 @@ wl_seat_get_keyboard(struct wl_seat *wl_seat) { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat, - WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); return (struct wl_keyboard *) id; } @@ -4011,8 +3999,8 @@ wl_seat_get_touch(struct wl_seat *wl_seat) { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat, - WL_SEAT_GET_TOUCH, &wl_touch_interface, NULL); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); return (struct wl_touch *) id; } @@ -4026,10 +4014,8 @@ wl_seat_get_touch(struct wl_seat *wl_seat) static inline void wl_seat_release(struct wl_seat *wl_seat) { - wl_proxy_marshal((struct wl_proxy *) wl_seat, - WL_SEAT_RELEASE); - - wl_proxy_destroy((struct wl_proxy *) wl_seat); + wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_POINTER_ERROR_ENUM @@ -4506,8 +4492,8 @@ wl_pointer_destroy(struct wl_pointer *wl_pointer) static inline void wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) { - wl_proxy_marshal((struct wl_proxy *) wl_pointer, - WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y); + wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, + WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y); } /** @@ -4522,10 +4508,8 @@ wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_ static inline void wl_pointer_release(struct wl_pointer *wl_pointer) { - wl_proxy_marshal((struct wl_proxy *) wl_pointer, - WL_POINTER_RELEASE); - - wl_proxy_destroy((struct wl_proxy *) wl_pointer); + wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, + WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM @@ -4753,10 +4737,8 @@ wl_keyboard_destroy(struct wl_keyboard *wl_keyboard) static inline void wl_keyboard_release(struct wl_keyboard *wl_keyboard) { - wl_proxy_marshal((struct wl_proxy *) wl_keyboard, - WL_KEYBOARD_RELEASE); - - wl_proxy_destroy((struct wl_proxy *) wl_keyboard); + wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard, + WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY); } /** @@ -4997,10 +4979,8 @@ wl_touch_destroy(struct wl_touch *wl_touch) static inline void wl_touch_release(struct wl_touch *wl_touch) { - wl_proxy_marshal((struct wl_proxy *) wl_touch, - WL_TOUCH_RELEASE); - - wl_proxy_destroy((struct wl_proxy *) wl_touch); + wl_proxy_marshal_flags((struct wl_proxy *) wl_touch, + WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_OUTPUT_SUBPIXEL_ENUM @@ -5282,10 +5262,8 @@ wl_output_destroy(struct wl_output *wl_output) static inline void wl_output_release(struct wl_output *wl_output) { - wl_proxy_marshal((struct wl_proxy *) wl_output, - WL_OUTPUT_RELEASE); - - wl_proxy_destroy((struct wl_proxy *) wl_output); + wl_proxy_marshal_flags((struct wl_proxy *) wl_output, + WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY); } #define WL_REGION_DESTROY 0 @@ -5334,10 +5312,8 @@ wl_region_get_version(struct wl_region *wl_region) static inline void wl_region_destroy(struct wl_region *wl_region) { - wl_proxy_marshal((struct wl_proxy *) wl_region, - WL_REGION_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_region); + wl_proxy_marshal_flags((struct wl_proxy *) wl_region, + WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY); } /** @@ -5348,8 +5324,8 @@ wl_region_destroy(struct wl_region *wl_region) static inline void wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) { - wl_proxy_marshal((struct wl_proxy *) wl_region, - WL_REGION_ADD, x, y, width, height); + wl_proxy_marshal_flags((struct wl_proxy *) wl_region, + WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); } /** @@ -5360,8 +5336,8 @@ wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, static inline void wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) { - wl_proxy_marshal((struct wl_proxy *) wl_region, - WL_REGION_SUBTRACT, x, y, width, height); + wl_proxy_marshal_flags((struct wl_proxy *) wl_region, + WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); } #ifndef WL_SUBCOMPOSITOR_ERROR_ENUM @@ -5417,10 +5393,8 @@ wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor) static inline void wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor) { - wl_proxy_marshal((struct wl_proxy *) wl_subcompositor, - WL_SUBCOMPOSITOR_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_subcompositor); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, + WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY); } /** @@ -5439,8 +5413,8 @@ wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struc { struct wl_proxy *id; - id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_subcompositor, - WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, NULL, surface, parent); + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, + WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent); return (struct wl_subsurface *) id; } @@ -5520,10 +5494,8 @@ wl_subsurface_get_version(struct wl_subsurface *wl_subsurface) static inline void wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) { - wl_proxy_marshal((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) wl_subsurface); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY); } /** @@ -5549,8 +5521,8 @@ wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) static inline void wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) { - wl_proxy_marshal((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_POSITION, x, y); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y); } /** @@ -5575,8 +5547,8 @@ wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32 static inline void wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) { - wl_proxy_marshal((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_PLACE_ABOVE, sibling); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); } /** @@ -5588,8 +5560,8 @@ wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface static inline void wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) { - wl_proxy_marshal((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_PLACE_BELOW, sibling); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); } /** @@ -5612,8 +5584,8 @@ wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface static inline void wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) { - wl_proxy_marshal((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_SYNC); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); } /** @@ -5642,8 +5614,8 @@ wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) static inline void wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) { - wl_proxy_marshal((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_DESYNC); + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); } #ifdef __cplusplus diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h index d4247570..348d2dc2 100644 --- a/tests/data/small-client-core.h +++ b/tests/data/small-client-core.h @@ -159,8 +159,8 @@ intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t { struct wl_proxy *untyped_new; - untyped_new = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) intf_A, - INTF_A_RQ1, interface, version, interface->name, version, NULL); + untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, + INTF_A_RQ1, interface, version, 0, interface->name, version, NULL); return (void *) untyped_new; } @@ -173,8 +173,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix { struct wl_proxy *typed_new; - typed_new = wl_proxy_marshal_constructor((struct wl_proxy *) intf_A, - INTF_A_RQ2, &intf_not_here_interface, NULL, str, i, u, f, fd, obj); + typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, + INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj); return (struct intf_not_here *) typed_new; } @@ -185,10 +185,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix static inline void intf_A_destroy(struct intf_A *intf_A) { - wl_proxy_marshal((struct wl_proxy *) intf_A, - INTF_A_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) intf_A); + wl_proxy_marshal_flags((struct wl_proxy *) intf_A, + INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY); } #ifdef __cplusplus diff --git a/tests/data/small-client.h b/tests/data/small-client.h index 2a1f961d..8c6abc50 100644 --- a/tests/data/small-client.h +++ b/tests/data/small-client.h @@ -159,8 +159,8 @@ intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t { struct wl_proxy *untyped_new; - untyped_new = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) intf_A, - INTF_A_RQ1, interface, version, interface->name, version, NULL); + untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, + INTF_A_RQ1, interface, version, 0, interface->name, version, NULL); return (void *) untyped_new; } @@ -173,8 +173,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix { struct wl_proxy *typed_new; - typed_new = wl_proxy_marshal_constructor((struct wl_proxy *) intf_A, - INTF_A_RQ2, &intf_not_here_interface, NULL, str, i, u, f, fd, obj); + typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, + INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj); return (struct intf_not_here *) typed_new; } @@ -185,10 +185,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix static inline void intf_A_destroy(struct intf_A *intf_A) { - wl_proxy_marshal((struct wl_proxy *) intf_A, - INTF_A_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) intf_A); + wl_proxy_marshal_flags((struct wl_proxy *) intf_A, + INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY); } #ifdef __cplusplus From f736f11f99c73a3bf0d9089f5b6bc60e60b84bca Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 6 Aug 2021 13:16:55 -0500 Subject: [PATCH 0752/1152] connection: Rename wl_buffer struct wl_buffer has other meaning in wayland, thus making this a pretty confusing structure name. Function names like wl_buffer_put() just compound the confusion. Rename the struct and the associated functions (none of which are called from outside this file anyway). The struct retains a wl_ prefix, as is the custom for wayland internal data structures. The function names have not retained this prefix, as we have many static function that aren't prefixed. Signed-off-by: Derek Foreman --- src/connection.c | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/connection.c b/src/connection.c index 1210772d..ad16eeef 100644 --- a/src/connection.c +++ b/src/connection.c @@ -54,7 +54,7 @@ div_roundup(uint32_t n, size_t a) return (uint32_t) (((uint64_t) n + (a - 1)) / a); } -struct wl_buffer { +struct wl_ring_buffer { char data[4096]; uint32_t head, tail; }; @@ -65,14 +65,14 @@ struct wl_buffer { #define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t))) struct wl_connection { - struct wl_buffer in, out; - struct wl_buffer fds_in, fds_out; + struct wl_ring_buffer in, out; + struct wl_ring_buffer fds_in, fds_out; int fd; int want_flush; }; static int -wl_buffer_put(struct wl_buffer *b, const void *data, size_t count) +ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count) { uint32_t head, size; @@ -98,7 +98,7 @@ wl_buffer_put(struct wl_buffer *b, const void *data, size_t count) } static void -wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count) +ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) { uint32_t head, tail; @@ -122,7 +122,7 @@ wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count) } static void -wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count) +ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) { uint32_t head, tail; @@ -146,7 +146,7 @@ wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count) } static void -wl_buffer_copy(struct wl_buffer *b, void *data, size_t count) +ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count) { uint32_t tail, size; @@ -161,7 +161,7 @@ wl_buffer_copy(struct wl_buffer *b, void *data, size_t count) } static uint32_t -wl_buffer_size(struct wl_buffer *b) +ring_buffer_size(struct wl_ring_buffer *b) { return b->head - b->tail; } @@ -181,16 +181,16 @@ wl_connection_create(int fd) } static void -close_fds(struct wl_buffer *buffer, int max) +close_fds(struct wl_ring_buffer *buffer, int max) { int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count; size_t size; - size = wl_buffer_size(buffer); + size = ring_buffer_size(buffer); if (size == 0) return; - wl_buffer_copy(buffer, fds, size); + ring_buffer_copy(buffer, fds, size); count = size / sizeof fds[0]; if (max > 0 && max < count) count = max; @@ -221,7 +221,7 @@ wl_connection_destroy(struct wl_connection *connection) void wl_connection_copy(struct wl_connection *connection, void *data, size_t size) { - wl_buffer_copy(&connection->in, data, size); + ring_buffer_copy(&connection->in, data, size); } void @@ -231,12 +231,12 @@ wl_connection_consume(struct wl_connection *connection, size_t size) } static void -build_cmsg(struct wl_buffer *buffer, char *data, int *clen) +build_cmsg(struct wl_ring_buffer *buffer, char *data, int *clen) { struct cmsghdr *cmsg; size_t size; - size = wl_buffer_size(buffer); + size = ring_buffer_size(buffer); if (size > MAX_FDS_OUT * sizeof(int32_t)) size = MAX_FDS_OUT * sizeof(int32_t); @@ -245,7 +245,7 @@ build_cmsg(struct wl_buffer *buffer, char *data, int *clen) cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(size); - wl_buffer_copy(buffer, CMSG_DATA(cmsg), size); + ring_buffer_copy(buffer, CMSG_DATA(cmsg), size); *clen = cmsg->cmsg_len; } else { *clen = 0; @@ -253,7 +253,7 @@ build_cmsg(struct wl_buffer *buffer, char *data, int *clen) } static int -decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg) +decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg) { struct cmsghdr *cmsg; size_t size, max, i; @@ -266,13 +266,13 @@ decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg) continue; size = cmsg->cmsg_len - CMSG_LEN(0); - max = sizeof(buffer->data) - wl_buffer_size(buffer); + max = sizeof(buffer->data) - ring_buffer_size(buffer); if (size > max || overflow) { overflow = 1; size /= sizeof(int32_t); for (i = 0; i < size; i++) close(((int*)CMSG_DATA(cmsg))[i]); - } else if (wl_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) { + } else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) { return -1; } } @@ -299,7 +299,7 @@ wl_connection_flush(struct wl_connection *connection) tail = connection->out.tail; while (connection->out.head - connection->out.tail > 0) { - wl_buffer_get_iov(&connection->out, iov, &count); + ring_buffer_get_iov(&connection->out, iov, &count); build_cmsg(&connection->fds_out, cmsg, &clen); @@ -332,7 +332,7 @@ wl_connection_flush(struct wl_connection *connection) uint32_t wl_connection_pending_input(struct wl_connection *connection) { - return wl_buffer_size(&connection->in); + return ring_buffer_size(&connection->in); } int @@ -343,12 +343,12 @@ wl_connection_read(struct wl_connection *connection) char cmsg[CLEN]; int len, count, ret; - if (wl_buffer_size(&connection->in) >= sizeof(connection->in.data)) { + if (ring_buffer_size(&connection->in) >= sizeof(connection->in.data)) { errno = EOVERFLOW; return -1; } - wl_buffer_put_iov(&connection->in, iov, &count); + ring_buffer_put_iov(&connection->in, iov, &count); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -385,7 +385,7 @@ wl_connection_write(struct wl_connection *connection, return -1; } - if (wl_buffer_put(&connection->out, data, count) < 0) + if (ring_buffer_put(&connection->out, data, count) < 0) return -1; connection->want_flush = 1; @@ -404,7 +404,7 @@ wl_connection_queue(struct wl_connection *connection, return -1; } - return wl_buffer_put(&connection->out, data, count); + return ring_buffer_put(&connection->out, data, count); } int @@ -429,13 +429,13 @@ wl_connection_get_fd(struct wl_connection *connection) static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { - if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) { + if (ring_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) { connection->want_flush = 1; if (wl_connection_flush(connection) < 0) return -1; } - return wl_buffer_put(&connection->fds_out, &fd, sizeof fd); + return ring_buffer_put(&connection->fds_out, &fd, sizeof fd); } const char * @@ -849,7 +849,7 @@ wl_connection_demarshal(struct wl_connection *connection, goto err; } - wl_buffer_copy(&connection->fds_in, &fd, sizeof fd); + ring_buffer_copy(&connection->fds_in, &fd, sizeof fd); connection->fds_in.tail += sizeof fd; closure->args[i].h = fd; break; From bf98c1a8f2872d3da2be895d9a7f56ada65d43d5 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 26 Aug 2021 14:50:59 -0500 Subject: [PATCH 0753/1152] tests: Destroy custom global object Destroy our custom global object at end of run so we no longer "leak" it. Signed-off-by: Derek Foreman --- tests/test-compositor.c | 9 +++++---- tests/test-compositor.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 468ee56d..103ddc85 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -329,7 +329,6 @@ struct display * display_create(void) { struct display *d = NULL; - struct wl_global *g; const char *socket_name; int stat = 0; @@ -350,9 +349,10 @@ display_create(void) wl_list_init(&d->waiting_for_resume); d->wfr_num = 0; - g = wl_global_create(d->wl_display, &test_compositor_interface, - 1, d, tc_bind); - assert(g && "Creating test global failed"); + d->test_global = wl_global_create(d->wl_display, + &test_compositor_interface, + 1, d, tc_bind); + assert(d->test_global && "Creating test global failed"); return d; } @@ -410,6 +410,7 @@ display_destroy(struct display *d) free(cl); } + wl_global_destroy(d->test_global); wl_display_destroy(d->wl_display); free(d); diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 180dad25..f763fef3 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -46,6 +46,7 @@ struct client_info { struct display { struct wl_display *wl_display; + struct wl_global *test_global; struct wl_list clients; uint32_t clients_no; From 8ec25be6dbd1d5ca4e4b55ce573424a33c79f361 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 7 Jun 2021 11:12:18 +0100 Subject: [PATCH 0754/1152] os-wrappers-test: Handle fcntl() being declared as a macro On some systems (e.g. FreeBSD with the latest epoll-shim), fcntl is declared as a macro instead of a function. Wrap the definition here in parantheses to avoid function-macro expansion. Signed-off-by: Alex Richardson --- tests/os-wrappers-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 0fd7853d..51eaa298 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -100,7 +100,7 @@ socket(int domain, int type, int protocol) } __attribute__ ((visibility("default"))) int -fcntl(int fd, int cmd, ...) +(fcntl)(int fd, int cmd, ...) { va_list ap; int arg; From c65f852fc8b2742e4944f58f9bd0f1e0b44b983a Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 15 Mar 2021 22:18:14 +0000 Subject: [PATCH 0755/1152] Use epoll-shim to emulate epoll(7) on FreeBSD FreeBSD does not provide epoll(7) and instead requires an external library, epoll-shim, that implements epoll() using kqueue(2) Co-authored-by: Jan Beich Signed-off-by: Alex Richardson --- meson.build | 10 +++++++++- src/meson.build | 6 ++++-- tests/meson.build | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 714a86d8..427aacf5 100644 --- a/meson.build +++ b/meson.build @@ -43,6 +43,14 @@ foreach f: have_funcs endforeach if get_option('libraries') + if host_machine.system() == 'freebsd' + # When building for FreeBSD, epoll(7) is provided by a userspace + # wrapper around kqueue(2). + epoll_dep = dependency('epoll-shim') + else + # Otherwise, assume that epoll(7) is supported natively. + epoll_dep = [] + endif ffi_dep = dependency('libffi') decls = [ @@ -52,7 +60,7 @@ if get_option('libraries') ] foreach d: decls - if not cc.has_header_symbol(d['header'], d['symbol']) + if not cc.has_header_symbol(d['header'], d['symbol'], dependencies: epoll_dep) error('@0@ is needed to compile Wayland libraries'.format(d['symbol'])) endif endforeach diff --git a/src/meson.build b/src/meson.build index ec00d816..a5d74109 100644 --- a/src/meson.build +++ b/src/meson.build @@ -89,7 +89,7 @@ if get_option('libraries') 'connection.c', 'wayland-os.c' ], - dependencies: [ ffi_dep, rt_dep ] + dependencies: [ epoll_dep, ffi_dep, rt_dep ] ) wayland_private_dep = declare_dependency( @@ -163,6 +163,7 @@ if get_option('libraries') ], version: '0.1.0', dependencies: [ + epoll_dep, ffi_dep, wayland_private_dep, wayland_util_dep, @@ -177,7 +178,7 @@ if get_option('libraries') wayland_server_dep = declare_dependency( link_with: wayland_server, include_directories: [ root_inc, include_directories('.') ], - dependencies: [ ffi_dep, mathlib_dep, threads_dep ], + dependencies: [ epoll_dep, ffi_dep, mathlib_dep, threads_dep ], sources: [ wayland_server_protocol_core_h, wayland_server_protocol_h @@ -206,6 +207,7 @@ if get_option('libraries') ], version: '0.3.0', dependencies: [ + epoll_dep, ffi_dep, wayland_private_dep, wayland_util_dep, diff --git a/tests/meson.build b/tests/meson.build index 2e11af4e..58794e7d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -9,6 +9,7 @@ test_runner = static_library( dependencies: [ cc.find_library('dl', required: false), dependency('threads'), + epoll_dep, ffi_dep, wayland_util_dep, wayland_private_dep, @@ -154,7 +155,7 @@ tests = { foreach test_name, test_extra_sources: tests test_sources = [ test_name + '.c' ] + test_extra_sources - test_deps = [test_runner_dep] + test_deps = [test_runner_dep, epoll_dep] bin = executable(test_name, test_sources, dependencies: test_deps) test( test_name, From c260d57750dada26d675218dac997333d41368d1 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 27 Jul 2021 14:00:38 +0100 Subject: [PATCH 0756/1152] gitlab-ci: update ci-templates to the latest commit This is in preparation for adding FreeBSD CI support. Signed-off-by: Alex Richardson --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c8fdf090..a59dc76f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ # API changes. If you need new features from ci-templates you must bump # this to the current SHA you require from the ci-templates repo, however # be aware that you may need to account for API changes when doing so. -.templates_sha: &template_sha 290b79e0e78eab67a83766f4e9691be554fc4afd # see https://docs.gitlab.com/ee/ci/yaml/#includefile +.templates_sha: &template_sha 567700e483aabed992d0a4fea84994a0472deff6 # see https://docs.gitlab.com/ee/ci/yaml/#includefile include: # Debian container builder template From 3288a076ebc2bee1b5c16d51d62bd1371ca30387 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 27 Aug 2021 10:03:56 +0100 Subject: [PATCH 0757/1152] gitlab-ci: remove duplicated lines in ci-templates include The file key can have multiple values, so we don't need another "project". Signed-off-by: Alex Richardson --- .gitlab-ci.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a59dc76f..f40674df 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -44,14 +44,11 @@ .templates_sha: &template_sha 567700e483aabed992d0a4fea84994a0472deff6 # see https://docs.gitlab.com/ee/ci/yaml/#includefile include: - # Debian container builder template - project: 'freedesktop/ci-templates' ref: *template_sha - file: '/templates/debian.yml' - # ci-fairy template - - project: 'freedesktop/ci-templates' - ref: *template_sha - file: '/templates/ci-fairy.yml' + file: + - '/templates/debian.yml' + - '/templates/ci-fairy.yml' variables: FDO_UPSTREAM_REPO: wayland/wayland From c0e8990e65b27412c64654794cb20e79552e5ed7 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 5 Aug 2021 17:37:26 +0100 Subject: [PATCH 0758/1152] gitlab-ci: Fix copy-paste error in a comment Signed-off-by: Alex Richardson --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f40674df..748e3946 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,6 @@ -# This file uses the freedesktop ci-templates to build Weston and run our +# This file uses the freedesktop ci-templates to build Wayland and run our # tests in CI. -# +# # ci-templates uses a multi-stage build process. First, the base container # image is built which contains the core distribution, the toolchain, and # all our build dependencies. This container is aggressively cached; if a From f1552700ce57b9e7d0a7d4067b28061dc5b9f336 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 27 Jul 2021 14:01:03 +0100 Subject: [PATCH 0759/1152] gitlab-ci: add junit reports to the debian builder Signed-off-by: Alex Richardson --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 748e3946..94d1e4ce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -226,7 +226,8 @@ armv7-debian-container_prep: paths: - build-*/meson-logs - prefix-* - + reports: + junit: build-*/meson-logs/testlog.junit.xml # Full build and test. x86_64-debian-build: From 54b237a61257a41d35d018c5871331bdf1df77a6 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 15 Mar 2021 22:21:12 +0000 Subject: [PATCH 0760/1152] Support reading ucred from the socket on FreeBSD On FreeBSD we have to use getsockopt(fd, SOL_LOCAL, LOCAL_PEERCRED) instead. This change is based on a downstream patch in FreeBSD ports. Co-authored-by: Greg V Co-authored-by: Koop Mast Signed-off-by: Alex Richardson --- meson.build | 3 ++- src/wayland-os.c | 47 +++++++++++++++++++++++++++++++++++++++++++- src/wayland-os.h | 6 ++++++ src/wayland-server.c | 18 ++++++++--------- 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 427aacf5..aeb171e4 100644 --- a/meson.build +++ b/meson.build @@ -26,7 +26,7 @@ add_project_arguments( language: 'c' ) -foreach h: [ 'sys/prctl.h' ] +foreach h: [ 'sys/prctl.h', 'sys/ucred.h' ] config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) endforeach @@ -41,6 +41,7 @@ have_funcs = [ foreach f: have_funcs config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f)) endforeach +config_h.set10('HAVE_XUCRED_CR_PID', cc.has_member('struct xucred', 'cr_pid', prefix : '#include ')) if get_option('libraries') if host_machine.system() == 'freebsd' diff --git a/src/wayland-os.c b/src/wayland-os.c index 1e4a23db..46db2678 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -25,14 +25,19 @@ #define _GNU_SOURCE +#include "../config.h" + #include #include #include #include #include #include +#include +#ifdef HAVE_SYS_UCRED_H +#include +#endif -#include "../config.h" #include "wayland-os.h" static int @@ -72,6 +77,46 @@ wl_os_socket_cloexec(int domain, int type, int protocol) return set_cloexec_or_close(fd); } +#if defined(__FreeBSD__) +int +wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) +{ + socklen_t len; + struct xucred ucred; + + len = sizeof(ucred); + if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &ucred, &len) < 0 || + ucred.cr_version != XUCRED_VERSION) + return -1; + *uid = ucred.cr_uid; + *gid = ucred.cr_gid; +#if HAVE_XUCRED_CR_PID + /* Since https://cgit.freebsd.org/src/commit/?id=c5afec6e895a */ + *pid = ucred.cr_pid; +#else + *pid = 0; +#endif + return 0; +} +#elif defined(SO_PEERCRED) +int +wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) +{ + socklen_t len; + struct ucred ucred; + + len = sizeof(ucred); + if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) + return -1; + *uid = ucred.uid; + *gid = ucred.gid; + *pid = ucred.pid; + return 0; +} +#else +#error "Don't know how to read ucred on this platform" +#endif + int wl_os_dupfd_cloexec(int fd, int minfd) { diff --git a/src/wayland-os.h b/src/wayland-os.h index af376405..ccd76ba6 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -26,9 +26,15 @@ #ifndef WAYLAND_OS_H #define WAYLAND_OS_H +#include +#include + int wl_os_socket_cloexec(int domain, int type, int protocol); +int +wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid); + int wl_os_dupfd_cloexec(int fd, int minfd); diff --git a/src/wayland-server.c b/src/wayland-server.c index 4783ab3e..4778d853 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -78,7 +78,9 @@ struct wl_client { struct wl_list link; struct wl_map objects; struct wl_priv_signal destroy_signal; - struct ucred ucred; + pid_t pid; + uid_t uid; + gid_t gid; int error; struct wl_priv_signal resource_created_signal; }; @@ -314,7 +316,7 @@ wl_resource_post_error(struct wl_resource *resource, static void destroy_client_with_error(struct wl_client *client, const char *reason) { - wl_log("%s (pid %u)\n", reason, client->ucred.pid); + wl_log("%s (pid %u)\n", reason, client->pid); wl_client_destroy(client); } @@ -513,7 +515,6 @@ WL_EXPORT struct wl_client * wl_client_create(struct wl_display *display, int fd) { struct wl_client *client; - socklen_t len; client = zalloc(sizeof *client); if (client == NULL) @@ -528,9 +529,8 @@ wl_client_create(struct wl_display *display, int fd) if (!client->source) goto err_client; - len = sizeof client->ucred; - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, - &client->ucred, &len) < 0) + if (wl_os_socket_peercred(fd, &client->uid, &client->gid, + &client->pid) != 0) goto err_source; client->connection = wl_connection_create(fd); @@ -586,11 +586,11 @@ wl_client_get_credentials(struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid) { if (pid) - *pid = client->ucred.pid; + *pid = client->pid; if (uid) - *uid = client->ucred.uid; + *uid = client->uid; if (gid) - *gid = client->ucred.gid; + *gid = client->gid; } /** Get the file descriptor for the client From 5a981ee823795a61372c46ed7f6d2582450ee0af Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 15 Mar 2021 22:25:52 +0000 Subject: [PATCH 0761/1152] shm: Add mmap+memmove fallback if mremap() does not exist Some operating systems (e.g. FreeBSD) do not implement mremap. In that case we can grow the mapping by trying to map adjacent memory. If that fails we can fall back to creating a new larger mapping and moving the old memory contents there. Co-authored-by: Koop Mast Signed-off-by: Alex Richardson --- meson.build | 1 + src/wayland-os.c | 30 +++++++++++++++++++++++++++++ src/wayland-os.h | 4 ++++ src/wayland-shm.c | 48 ++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 74 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index aeb171e4..239bff7c 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,7 @@ have_funcs = [ 'posix_fallocate', 'prctl', 'memfd_create', + 'mremap', 'strndup', ] foreach f: have_funcs diff --git a/src/wayland-os.c b/src/wayland-os.c index 46db2678..44d4e725 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include #ifdef HAVE_SYS_UCRED_H #include @@ -210,3 +212,31 @@ wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) fd = accept(sockfd, addr, addrlen); return set_cloexec_or_close(fd); } + +/* + * Fallback function for operating systems that don't implement + * mremap(MREMAP_MAYMOVE). + */ +void * +wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size, + ssize_t new_size, int prot, int flags) +{ + void *result; + /* + * We could try mapping a new block immediately after the current one + * with MAP_FIXED, however that is not guaranteed to work and breaks + * on CHERI-enabled architectures since the data pointer will still + * have the bounds of the previous allocation. As this is not a + * performance-critical path, we always map a new region and copy the + * old data to the new region. + */ + result = mmap(NULL, new_size, prot, flags, fd, 0); + if (result != MAP_FAILED) { + /* Copy the data over and unmap the old mapping. */ + memcpy(result, old_data, *old_size); + if (munmap(old_data, *old_size) == 0) { + *old_size = 0; /* successfully unmapped old data. */ + } + } + return result; +} diff --git a/src/wayland-os.h b/src/wayland-os.h index ccd76ba6..068fd2fe 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -47,6 +47,10 @@ wl_os_epoll_create_cloexec(void); int wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +void * +wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size, + ssize_t new_size, int prot, int flags); + /* * The following are for wayland-os.c and the unit tests. diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 671549c3..5ff794aa 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -45,6 +45,7 @@ #include #include +#include "wayland-os.h" #include "wayland-util.h" #include "wayland-private.h" #include "wayland-server.h" @@ -61,8 +62,12 @@ struct wl_shm_pool { int internal_refcount; int external_refcount; char *data; - int32_t size; - int32_t new_size; + ssize_t size; + ssize_t new_size; + /* The following three fields are needed for mremap() emulation. */ + int mmap_fd; + int mmap_flags; + int mmap_prot; bool sigbus_is_impossible; }; @@ -90,6 +95,26 @@ struct wl_shm_sigbus_data { int fallback_mapping_used; }; +static void * +shm_pool_grow_mapping(struct wl_shm_pool *pool) +{ + void *data; + +#ifdef MREMAP_MAYMOVE + data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); +#else + data = wl_os_mremap_maymove(pool->mmap_fd, pool->data, &pool->size, + pool->new_size, pool->mmap_prot, + pool->mmap_flags); + if (pool->size != 0) { + wl_resource_post_error(pool->resource, + WL_SHM_ERROR_INVALID_FD, + "leaked old mapping"); + } +#endif + return data; +} + static void shm_pool_finish_resize(struct wl_shm_pool *pool) { @@ -98,7 +123,7 @@ shm_pool_finish_resize(struct wl_shm_pool *pool) if (pool->size == pool->new_size) return; - data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); + data = shm_pool_grow_mapping(pool); if (data == MAP_FAILED) { wl_resource_post_error(pool->resource, WL_SHM_ERROR_INVALID_FD, @@ -127,6 +152,7 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external) return; munmap(pool->data, pool->size); + close(pool->mmap_fd); free(pool); } @@ -274,6 +300,8 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, { struct wl_shm_pool *pool; int seals; + int prot; + int flags; if (size <= 0) { wl_resource_post_error(resource, @@ -301,17 +329,19 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, pool->external_refcount = 0; pool->size = size; pool->new_size = size; - pool->data = mmap(NULL, size, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + prot = PROT_READ | PROT_WRITE; + flags = MAP_SHARED; + pool->data = mmap(NULL, size, prot, flags, fd, 0); if (pool->data == MAP_FAILED) { - wl_resource_post_error(resource, - WL_SHM_ERROR_INVALID_FD, + wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, "failed mmap fd %d: %s", fd, strerror(errno)); goto err_free; } - close(fd); - + /* We may need to keep the fd, prot and flags to emulate mremap(). */ + pool->mmap_fd = fd; + pool->mmap_prot = prot; + pool->mmap_flags = flags; pool->resource = wl_resource_create(client, &wl_shm_pool_interface, 1, id); if (!pool->resource) { From 644efe9517eb48d18decc33d5bed5276fcdd2f5a Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 18 Mar 2021 09:25:58 +0000 Subject: [PATCH 0762/1152] Use /dev/fd instead of /proc/self/fd /dev/fd exists on all operating systems I can test (Linux, FreeBSD, macOS), whereas /proc/self/fd only appears to exist on Linux. Signed-off-by: Alex Richardson --- tests/test-helpers.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/test-helpers.c b/tests/test-helpers.c index 20b66903..4cdd1fca 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -48,8 +48,12 @@ count_open_fds(void) struct dirent *ent; int count = 0; - dir = opendir("/proc/self/fd"); - assert(dir && "opening /proc/self/fd failed."); + /* + * Using /dev/fd instead of /proc/self/fd should allow this code to + * work on non-Linux operating systems. + */ + dir = opendir("/dev/fd"); + assert(dir && "opening /dev/fd failed."); errno = 0; while ((ent = readdir(dir))) { @@ -58,7 +62,7 @@ count_open_fds(void) continue; count++; } - assert(errno == 0 && "reading /proc/self/fd failed."); + assert(errno == 0 && "reading /dev/fd failed."); closedir(dir); From bb928288077ff0fcab50a881e1ade2cf249f7a14 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 15 Mar 2021 22:37:49 +0000 Subject: [PATCH 0763/1152] test-runner: Implement is_debugger_attached() for FreeBSD FreeBSD provides a PROC_TRACE_STATUS procctl(2) to detect this directly. Signed-off-by: Alex Richardson --- meson.build | 2 +- tests/test-runner.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 239bff7c..a116d9d8 100644 --- a/meson.build +++ b/meson.build @@ -26,7 +26,7 @@ add_project_arguments( language: 'c' ) -foreach h: [ 'sys/prctl.h', 'sys/ucred.h' ] +foreach h: [ 'sys/prctl.h', 'sys/procctl.h', 'sys/ucred.h' ] config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) endforeach diff --git a/tests/test-runner.c b/tests/test-runner.c index 8f084458..c0247b57 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -22,6 +22,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "../config.h" #define _GNU_SOURCE @@ -36,11 +37,16 @@ #include #include #include +#include #include +#ifdef HAVE_SYS_PROCCTL_H +#include +#elif defined(HAVE_SYS_PRCTL_H) #include #ifndef PR_SET_PTRACER # define PR_SET_PTRACER 0x59616d61 #endif +#endif #include "test-runner.h" @@ -226,6 +232,21 @@ stderr_reset_color(void) * Returns: 1 if a debugger is confirmed present; 0 if no debugger is * present or if it can't be determined. */ +#if defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_STATUS) +static int +is_debugger_attached(void) +{ + int rc; + int status; + rc = procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status); + if (rc == -1) { + perror("procctl"); + return 0; + } + /* -1=tracing disabled, 0=no debugger attached, >0=pid of debugger. */ + return status > 0; +} +#elif defined(HAVE_SYS_PRCTL_H) static int is_debugger_attached(void) { @@ -287,6 +308,7 @@ is_debugger_attached(void) return rc; } +#endif int main(int argc, char *argv[]) { From 42bf011f65a1aa5b7dcb664026b02c48170d07a5 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 7 Jun 2021 11:53:46 +0100 Subject: [PATCH 0764/1152] test-helpers: use sysctl() to count open fds on FreeBSD This allows running the tests on FreeBSD without mounting fdescfs. Previously you had to run `mount -t fdescfs -o linrdlnk null /dev/fd` to get file descriptors >=3 listed in /dev/fd. Signed-off-by: Alex Richardson --- tests/test-helpers.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test-helpers.c b/tests/test-helpers.c index 4cdd1fca..35357445 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -41,6 +41,27 @@ #include "test-runner.h" +#if defined(__FreeBSD__) +#include + +/* + * On FreeBSD, get file descriptor information using sysctl() since that does + * not depend on a mounted fdescfs (which provides /dev/fd/N for N > 2). + */ +int +count_open_fds(void) +{ + int error; + int nfds; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_NFDS, 0 }; + size_t len; + + len = sizeof(nfds); + error = sysctl(mib, 4, &nfds, &len, NULL, 0); + assert(error == 0 && "sysctl KERN_PROC_NFDS failed."); + return nfds; +} +#else int count_open_fds(void) { @@ -68,6 +89,7 @@ count_open_fds(void) return count; } +#endif void exec_fd_leak_check(int nr_expected_fds) From 382f368a2795cacbe0f3690f9bf5be749f9f0f5e Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 19 Mar 2021 10:02:41 +0000 Subject: [PATCH 0765/1152] Detect FreeBSD versions with broken MSG_CMSG_CLOEXEC If we are compiling against a version of FreeBSD where MSG_CMSG_CLOEXEC does not work, use the fallback directly. This was only fixed recently (in https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211). Signed-off-by: Alex Richardson --- meson.build | 16 ++++++++++++++++ src/wayland-os.c | 11 ++++++++++- tests/os-wrappers-test.c | 7 +++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a116d9d8..5cd978f1 100644 --- a/meson.build +++ b/meson.build @@ -43,6 +43,22 @@ foreach f: have_funcs config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f)) endforeach config_h.set10('HAVE_XUCRED_CR_PID', cc.has_member('struct xucred', 'cr_pid', prefix : '#include ')) +have_broken_msg_cmsg_cloexec = false +if host_machine.system() == 'freebsd' + have_broken_msg_cmsg_cloexec = not cc.compiles(''' +#include /* To get __FreeBSD_version. */ +#if __FreeBSD_version < 1300502 || \ + (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400006) +/* + * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 and + * 2021. Check if we are compiling against a version that includes the fix + * (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211). + */ +#error "Broken MSG_CMSG_CLOEXEC" +#endif +''', name : 'MSG_CMSG_CLOEXEC works correctly') +endif +config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec) if get_option('libraries') if host_machine.system() == 'freebsd' diff --git a/src/wayland-os.c b/src/wayland-os.c index 44d4e725..27c6035a 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -168,6 +168,15 @@ recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags) ssize_t wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) { +#if HAVE_BROKEN_MSG_CMSG_CLOEXEC + /* + * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 + * and 2021, so we have to use the non-MSG_CMSG_CLOEXEC fallback + * directly when compiling against a version that does not include the + * fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211). + */ +#pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.") +#else ssize_t len; len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC); @@ -175,7 +184,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) return len; if (errno != EINVAL) return -1; - +#endif return recvmsg_cloexec_fallback(sockfd, msg, flags); } diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 51eaa298..aadb93bc 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -23,6 +23,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "../config.h" #define _GNU_SOURCE @@ -341,7 +342,13 @@ do_os_wrappers_recvmsg_cloexec(int n) struct marshal_data data; data.nr_fds_begin = count_open_fds(); +#if HAVE_BROKEN_MSG_CMSG_CLOEXEC + /* We call the fallback directly on FreeBSD versions with a broken + * MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */ + data.wrapped_calls = 0; +#else data.wrapped_calls = n; +#endif setup_marshal_data(&data); data.nr_fds_conn = count_open_fds(); From ed423b8ac60a51afeb658c5d990fa672107f86d8 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 5 Aug 2021 09:08:04 +0100 Subject: [PATCH 0766/1152] Allow event-loop signal tests to pass on FreeBSD On Linux the signal will be immediately visible in the epoll_wait() call. However, on FreeBSD we may need a small delay between kill() call and the signal being visible to the kevent() call. This sometimes happens when the signal processing and kevent processing runs on different CPUs in the kernel, so becomes more likely when the system is under load (e.g. running all tests in parallel). See https://github.com/jiixyj/epoll-shim/pull/32 Signed-off-by: Alex Richardson --- tests/event-loop-test.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index cbeaf8eb..9d43c912 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -168,10 +168,22 @@ TEST(event_loop_signal) signal_callback, &got_it); assert(source); - wl_event_loop_dispatch(loop, 0); + assert(wl_event_loop_dispatch(loop, 0) == 0); assert(!got_it); - kill(getpid(), SIGUSR1); - wl_event_loop_dispatch(loop, 0); + assert(kill(getpid(), SIGUSR1) == 0); + /* + * On Linux the signal will be immediately visible in the epoll_wait() + * call. However, on FreeBSD we may need a small delay between kill() + * call and the signal being visible to the kevent() call. This + * sometimes happens when the signal processing and kevent processing + * runs on different CPUs, so becomes more likely when the system is + * under load (e.g. running all tests in parallel). + * See https://github.com/jiixyj/epoll-shim/pull/32 + * Passing 1ms as the timeout appears to avoid this race condition in + * all cases tested so far, but to be safe we use 1000ms which should + * be enough time even on a really slow (or emulated) system. + */ + assert(wl_event_loop_dispatch(loop, 1000) == 0); assert(got_it == 1); wl_event_source_remove(source); @@ -199,8 +211,12 @@ TEST(event_loop_multiple_same_signals) /* Try it more times */ for (i = 0; i < 5; ++i) { calls_no = 0; - kill(getpid(), SIGUSR1); - assert(wl_event_loop_dispatch(loop, 0) == 0); + assert(kill(getpid(), SIGUSR1) == 0); + /* + * We need a non-zero timeout here to allow the test to pass + * on non-Linux systems (see comment in event_loop_signal). + */ + assert(wl_event_loop_dispatch(loop, 1000) == 0); assert(calls_no == 2); } @@ -208,8 +224,12 @@ TEST(event_loop_multiple_same_signals) /* Try it again with one source */ calls_no = 0; - kill(getpid(), SIGUSR1); - assert(wl_event_loop_dispatch(loop, 0) == 0); + assert(kill(getpid(), SIGUSR1) == 0); + /* + * We need a non-zero timeout here to allow the test to pass + * on non-Linux systems (see comment in event_loop_signal). + */ + assert(wl_event_loop_dispatch(loop, 1000) == 0); assert(calls_no == 1); wl_event_source_remove(s2); From 4d473310eb7aeeb5ead9e4cd610832a48df77668 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 27 Jul 2021 14:05:06 +0100 Subject: [PATCH 0767/1152] gitlab-ci: add a FreeBSD test job This uses the new FreeBSD supported added in https://gitlab.freedesktop.org/freedesktop/ci-templates/-/merge_requests/114 After the latest series of commits, we should be able to compile and successfully run all tests, so adding this CI job will prevent any future FreeBSD regressions. Signed-off-by: Alex Richardson --- .gitlab-ci.yml | 92 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 94d1e4ce..8f70e1fd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,14 +48,12 @@ include: ref: *template_sha file: - '/templates/debian.yml' + - '/templates/freebsd.yml' - '/templates/ci-fairy.yml' variables: FDO_UPSTREAM_REPO: wayland/wayland FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH" - # bump this tag every time you change something which requires rebuilding the - # base image - FDO_DISTRIBUTION_TAG: "2021-08-03.0" # Define the build stages. These are used for UI grouping as well as @@ -77,6 +75,9 @@ stages: FDO_DISTRIBUTION_VERSION: buster FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.52.1' + # bump this tag every time you change something which requires rebuilding the + # base image + FDO_DISTRIBUTION_TAG: "2021-08-03.0" .debian-x86_64: extends: @@ -229,6 +230,37 @@ armv7-debian-container_prep: reports: junit: build-*/meson-logs/testlog.junit.xml +# Full build and test. +.do-build-qemu: + extends: + - .ci-rules + stage: "Build and test" + script: + # Start the VM and copy our workspace to the VM + - /app/vmctl start + - scp -r $PWD "vm:" + # The `set +e is needed to ensure that we always copy the meson logs back to + # the workspace to see details about the failed tests. + - | + set +e + /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}" + /app/vmctl exec "meson test --print-errorlogs -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4}" && touch .tests-successful + set -ex + scp -r vm:$BUILDDIR/meson-logs . + /app/vmctl exec "ninja -C $BUILDDIR install" + mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/ + # Finally, shut down the VM. + - /app/vmctl stop + - test -f .tests-successful || exit 1 + artifacts: + name: wayland-$CI_JOB_NAME + when: always + paths: + - meson-logs + - prefix-* + reports: + junit: meson-logs/testlog.junit.xml + # Full build and test. x86_64-debian-build: extends: @@ -262,3 +294,57 @@ armv7-release-debian-build: - .build-env-debian-armv7 - .do-build - .build-release + +# Base variables used for anything using a FreeBSD environment +.os-freebsd: + variables: + BUILD_OS: freebsd + FDO_DISTRIBUTION_VERSION: "13.0" + FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' + # bump this tag every time you change something which requires rebuilding the + # base image + FDO_DISTRIBUTION_TAG: "2021-08-05.0" + # Don't build documentation since installing the required tools massively + # increases the VM image (and therefore container) size. + MESON_ARGS: "-Ddocumentation=false" + +.freebsd-x86_64: + extends: + - .os-freebsd + variables: + BUILD_ARCH: "x86_64" + +x86_64-freebsd-container_prep: + extends: + - .ci-rules + - .freebsd-x86_64 + - .fdo.qemu-build@freebsd@x86_64 + stage: "Base container" + variables: + GIT_STRATEGY: none + +.build-env-freebsd-x86_64: + variables: + # Compiling with ASan+UBSan appears to trigger an infinite loop in the + # compiler shipped with FreeBSD 13.0, so we only use UBSan here. + # Additionally, sanitizers can't be used with b_lundef on FreeBSD. + MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false" + extends: + - .fdo.suffixed-image@freebsd + - .freebsd-x86_64 + - .build-env + needs: + - job: x86_64-freebsd-container_prep + artifacts: false + +# Full build and test. +x86_64-freebsd-build: + extends: + - .build-env-freebsd-x86_64 + - .do-build-qemu + +x86_64-release-freebsd-build: + extends: + - .build-env-freebsd-x86_64 + - .do-build-qemu + - .build-release From 7ef305d073f8d86aa7bf8a41ffcbbc7984b1f55a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 4 Sep 2021 16:18:43 +0200 Subject: [PATCH 0768/1152] protocol: mention that keymap mapping must be read-only It may be obvious that the mapping must be established in read-only mode, but it wasn't specified in the specification text. Signed-off-by: Simon Ser --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index a87e9dda..8c31cdc0 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2220,7 +2220,8 @@ This event provides a file descriptor to the client which can be - memory-mapped to provide a keyboard mapping description. + memory-mapped in read-only mode to provide a keyboard mapping + description. From version 7 onwards, the fd must be mapped with MAP_PRIVATE by the recipient, as MAP_SHARED may fail. From 616b4ae6180499b112734d544f217a2704509c13 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Thu, 16 Sep 2021 11:11:05 +0200 Subject: [PATCH 0769/1152] shm: Relax shm_pool_create_buffer() validity check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit shm_pool_create_buffer() can raise a false WL_SHM_ERROR_INVALID_STRIDE error under some circumstances because of integer division. Fix this by using a strict comparison operator instead of lower or equal. Signed-off-by: Olivier Fourdan Reviewed-by: Demi Marie Obenour Reviewed-by: Simon Ser Reviewed-by: Jonas Ådahl Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/235 --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 5ff794aa..27d5b008 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -213,7 +213,7 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, } if (offset < 0 || width <= 0 || height <= 0 || stride < width || - INT32_MAX / stride <= height || + INT32_MAX / stride < height || offset > pool->size - stride * height) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE, From c6c1bbe4abf9e5ce159442be22c1278d39844c08 Mon Sep 17 00:00:00 2001 From: Matt Hoosier Date: Wed, 29 Sep 2021 09:41:34 -0500 Subject: [PATCH 0770/1152] protocol: mention that buffers with alpha are assumed premultiplied This turns out to be the default assumption by compositors, OpenGL, and the DRM framework. Let's say it explicitly to avoid misinterpretation. See https://lists.freedesktop.org/archives/wayland-devel/2021-September/041990.html. Signed-off-by: Matt Hoosier --- protocol/wayland.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8c31cdc0..029db191 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -436,6 +436,10 @@ a height and can be attached to a wl_surface, but the mechanism by which a client provides and updates the contents is defined by the buffer factory interface. + + If the buffer uses a format that has an alpha channel, the alpha channel + is assumed to be premultiplied in the color channels unless otherwise + specified. From d564823cfdbdb62e4d84a3b2d15fa016fd7fb5dd Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 31 Aug 2021 18:59:33 +0900 Subject: [PATCH 0771/1152] server: stop wl_display event loop from any context Calling wl_display_terminate() will exit the wl_display event loop at the start of the next loop iteration. This works fine when wl_display_terminate() is called after the event loop wakes up from polling on the added event sources. If, however, it is called before polling starts, the event loop will not exit until one or more event sources trigger. Depending on the types of event sources, they may never trigger (or may not trigger for a long time), so the event loop may never exit. Add an extra event source to the wl_display event loop that will trigger whenever wl_display_terminate() is called, so that the event loop will always exit. Fixes #201 Signed-off-by: Damian Hobson-Garcia --- src/wayland-server.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ tests/display-test.c | 21 +++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 4778d853..6ae46891 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,9 @@ struct wl_display { wl_display_global_filter_func_t global_filter; void *global_filter_data; + + int terminate_efd; + struct wl_event_source *term_source; }; struct wl_global { @@ -1030,6 +1034,16 @@ bind_display(struct wl_client *client, struct wl_display *display) return 0; } +static int +handle_display_terminate(int fd, uint32_t mask, void *data) { + uint64_t term_event; + + if (read(fd, &term_event, sizeof(term_event)) < 0 && errno != EAGAIN) + return -1; + + return 0; +} + /** Create Wayland display object. * * \return The Wayland display object. Null if failed to create @@ -1058,6 +1072,19 @@ wl_display_create(void) return NULL; } + display->terminate_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (display->terminate_efd < 0) + goto err_eventfd; + + display->term_source = wl_event_loop_add_fd(display->loop, + display->terminate_efd, + WL_EVENT_READABLE, + handle_display_terminate, + NULL); + + if (display->term_source == NULL) + goto err_term_source; + wl_list_init(&display->global_list); wl_list_init(&display->socket_list); wl_list_init(&display->client_list); @@ -1076,6 +1103,13 @@ wl_display_create(void) wl_array_init(&display->additional_shm_formats); return display; + +err_term_source: + close(display->terminate_efd); +err_eventfd: + wl_event_loop_destroy(display->loop); + free(display); + return NULL; } static void @@ -1135,6 +1169,10 @@ wl_display_destroy(struct wl_display *display) wl_list_for_each_safe(s, next, &display->socket_list, link) { wl_socket_destroy(s); } + + close(display->terminate_efd); + wl_event_source_remove(display->term_source); + wl_event_loop_destroy(display->loop); wl_list_for_each_safe(global, gnext, &display->global_list, link) @@ -1351,7 +1389,13 @@ wl_display_get_event_loop(struct wl_display *display) WL_EXPORT void wl_display_terminate(struct wl_display *display) { + int ret; + uint64_t terminate = 1; + display->run = 0; + + ret = write(display->terminate_efd, &terminate, sizeof(terminate)); + assert (ret >= 0 || errno == EAGAIN); } WL_EXPORT void diff --git a/tests/display-test.c b/tests/display-test.c index 3db7c95a..763adc91 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1629,3 +1629,24 @@ TEST(global_remove) display_destroy(d); } + +static void +terminate_display(void *arg) +{ + struct wl_display *wl_display = arg; + wl_display_terminate(wl_display); +} + +TEST(no_source_terminate) +{ + struct display *d; + struct wl_event_loop *loop; + + d = display_create(); + loop = wl_display_get_event_loop(d->wl_display); + + wl_event_loop_add_idle(loop, terminate_display, d->wl_display); + + display_run(d); + display_destroy(d); +} From f00cfda73723c4854538f7c3145ccd4f0cf5107a Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sun, 1 Aug 2021 01:38:45 -0400 Subject: [PATCH 0772/1152] client: handle fcntl error on bad fd in wl_display_connect This makes wl_display_connect fail immediately instead of succeeding when the integer provided by WAYLAND_SOCKET does not refer to a valid file descriptor. Signed-off-by: Manuel Stoeckl --- src/wayland-client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 63ce0d01..66f60e31 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1246,7 +1246,9 @@ wl_display_connect(const char *name) errno = prev_errno; flags = fcntl(fd, F_GETFD); - if (flags != -1) + if (flags == -1 && errno == EBADF) + return NULL; + else if (flags != -1) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); unsetenv("WAYLAND_SOCKET"); } else { From fceabb7e9e167e1100c244bb4f460c8a346a5478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 22 Mar 2021 08:56:30 +0100 Subject: [PATCH 0773/1152] protocol: Add wl_surface.offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is meant to address the issue where the call to 'wl_surface.attach' is done by e.g. Vulkan, meaning applications cannot affect the values of the offset passed as the x and y arguments. The lack of ability to pass these is problematic when using the Vulkan for e.g. drawing DND surfaces, as the buffer offset is used to implement the drag icon hotspots. Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/148 Signed-off-by: Jonas Ådahl Reviewed-by: Simon Ser --- egl/wayland-egl.c | 14 ++++++++++++++ protocol/wayland.xml | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/egl/wayland-egl.c b/egl/wayland-egl.c index a60f8991..36a34712 100644 --- a/egl/wayland-egl.c +++ b/egl/wayland-egl.c @@ -35,6 +35,20 @@ #include "wayland-util.h" +/** Resize the EGL window + * + * \param egl_window A pointer to a struct wl_egl_window + * \param width The new width + * \param height The new height + * \param dx Offset on the X axis + * \param dy Offset on the Y axis + * + * Note that applications should prefer using the wl_surface.offset request if + * the associated wl_surface has the interface version 5 or higher. + * + * If the wl_surface.offset request is used, applications MUST pass 0 to both + * dx and dy. + */ WL_EXPORT void wl_egl_window_resize(struct wl_egl_window *egl_window, int width, int height, diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 029db191..675c102d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -187,7 +187,7 @@ - + A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple @@ -1337,7 +1337,7 @@ - + A surface is a rectangular area that may be displayed on zero or more outputs, and shown any number of times at the compositor's @@ -1389,6 +1389,7 @@ + @@ -1411,7 +1412,14 @@ buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which - directions the surface's size changes. + directions the surface's size changes. Setting anything other than 0 + as x and y arguments is discouraged, and should instead be replaced + with using the separate wl_surface.offset request. + + When the bound wl_surface version is 5 or higher, passing any + non-zero x or y is a protocol violation, and will result in an + 'invalid_offset' error being raised. To achieve equivalent semantics, + use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. @@ -1742,6 +1750,27 @@ + + + + + + The x and y arguments specify the location of the new pending + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface-local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. + + Surface location offset is double-buffered state, see + wl_surface.commit. + + This request is semantically equivalent to and the replaces the x and y + arguments in the wl_surface.attach request in wl_surface versions prior + to 5. See wl_surface.attach for details. + + + + From 0cdd2a5c54771d18dc3ec9d690b7fbb754b90dfd Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 10 Sep 2021 18:32:00 +0100 Subject: [PATCH 0774/1152] build: Include the Wayland minor version in libraries' ABI versions The ABI of a shared library on Linux is given by a major version, which is part of the SONAME and is incremented (rarely) on incompatible changes, and a minor version, which is part of the basename of the regular file to which the SONAME provides a symlink. Until now, the ABI minor version was hard-coded, which means we can't tell which of a pair of Wayland libraries is newer (and therefore likely to have more symbols and/or fewer bugs). libwayland-egl already had ABI major version 1, so we can use the "marketing" version number as the ABI major.minor version number directly, so Wayland 1.19.90 would produce libwayland-egl.so.1 -> libwayland-egl.so.1.19.90. libwayland-cursor and libwayland-server have ABI major version 0, and OS distributions don't like it when there's a SONAME bump for no good reason, so use their existing ABI major version together with the "marketing" minor version: libwayland-cursor.so.0 -> libwayland-cursor.so.0.19.90. If the Wayland major version number is incremented to 2, we'll have to rethink this, so add some error() to break the build if/when that happens. Assuming that Wayland 2.0 would involve breaking changes, the best way would probably to bump all the SONAMEs to libwayland-foo.so.2. Resolves: https://gitlab.freedesktop.org/wayland/wayland/-/issues/175 Signed-off-by: Simon McVittie --- cursor/meson.build | 13 ++++++++++++- egl/meson.build | 2 +- meson.build | 1 + src/meson.build | 18 +++++++++++++++--- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/cursor/meson.build b/cursor/meson.build index ae85ed9b..5393a59f 100644 --- a/cursor/meson.build +++ b/cursor/meson.build @@ -3,6 +3,15 @@ if icondir == '' icondir = join_paths(get_option('prefix'), get_option('datadir'), 'icons') endif +if wayland_version[0] != '1' + # The versioning used for the shared libraries assumes that the major + # version of Wayland as a whole will increase to 2 if and only if there + # is an ABI break, at which point we should probably bump the SONAME of + # all libraries to .so.2. For more details see + # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177 + error('We probably need to bump the SONAME of libwayland-cursor') +endif + wayland_cursor = library( 'wayland-cursor', sources: [ @@ -10,7 +19,9 @@ wayland_cursor = library( 'os-compatibility.c', 'xcursor.c', ], - version: '0.0.0', + # To avoid an unnecessary SONAME bump, wayland 1.x.y produces + # libwayland-cursor.so.0.x.y. + version: '.'.join(['0', wayland_version[1], wayland_version[2]]), dependencies: [ wayland_client_dep ], c_args: [ '-DICONDIR="@0@"'.format(icondir) ], install: true, diff --git a/egl/meson.build b/egl/meson.build index dee9b1dd..503ac953 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -5,7 +5,7 @@ wayland_egl = library( wayland_client_protocol_h ], include_directories: src_inc, - version: '1.0.0', + version: meson.project_version(), install: true ) diff --git a/meson.build b/meson.build index 5cd978f1..acc3d787 100644 --- a/meson.build +++ b/meson.build @@ -8,6 +8,7 @@ project( 'buildtype=debugoptimized' ] ) +wayland_version = meson.project_version().split('.') config_h = configuration_data() config_h.set_quoted('PACKAGE', meson.project_name()) diff --git a/src/meson.build b/src/meson.build index a5d74109..b76d4fee 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,4 +1,3 @@ -wayland_version = meson.project_version().split('.') wayland_version_h = configuration_data() wayland_version_h.set('WAYLAND_VERSION', meson.project_version()) wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int()) @@ -151,6 +150,15 @@ if get_option('libraries') output: 'wayland-protocol.c' ) + if wayland_version[0] != '1' + # The versioning used for the shared libraries assumes that the major + # version of Wayland as a whole will increase to 2 if and only if there + # is an ABI break, at which point we should probably bump the SONAME of + # all libraries to .so.2. For more details see + # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177 + error('We probably need to bump the SONAME of libwayland-server and -client') + endif + wayland_server = library( 'wayland-server', sources: [ @@ -161,7 +169,9 @@ if get_option('libraries') 'wayland-shm.c', 'event-loop.c' ], - version: '0.1.0', + # To avoid an unnecessary SONAME bump, wayland 1.x.y produces + # libwayland-server.so.0.x.y. + version: '.'.join(['0', wayland_version[1], wayland_version[2]]), dependencies: [ epoll_dep, ffi_dep, @@ -205,7 +215,9 @@ if get_option('libraries') wayland_protocol_c, 'wayland-client.c' ], - version: '0.3.0', + # To avoid an unnecessary SONAME bump, wayland 1.x.y produces + # libwayland-client.so.0.x.y. + version: '.'.join(['0', wayland_version[1], wayland_version[2]]), dependencies: [ epoll_dep, ffi_dep, From aa883215174f0b389c1b7999b6a19c2be2c05c99 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Sep 2021 15:36:14 +0200 Subject: [PATCH 0775/1152] protocol: add note about wl_output.done in events Mention that geometry, mode and scale wl_output events are followed by a done event. Signed-off-by: Simon Ser --- protocol/wayland.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 675c102d..6001adcf 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2560,6 +2560,9 @@ The physical size can be set to zero if it doesn't make sense for this output (e.g. for projectors or virtual outputs). + The geometry event will be followed by a done event (starting from + version 2). + Note: wl_output only advertises partial information about the output position and identification. Some compositors, for instance those not implementing a desktop-style output layout or those exposing virtual @@ -2621,6 +2624,9 @@ The vertical refresh rate can be set to zero if it doesn't make sense for this output (e.g. for virtual outputs). + The mode event will be followed by a done event (starting from + version 2). + Clients should not use the refresh rate to schedule frames. Instead, they should use the wl_surface.frame event or the presentation-time protocol. @@ -2667,6 +2673,8 @@ the scale of the output. That way the compositor can avoid scaling the surface, and the client can supply a higher detail image. + + The scale event will be followed by a done event. From 9c05e6c475e0f67519d88f285a971b5e51455a1d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 24 Jan 2021 12:26:53 +0100 Subject: [PATCH 0776/1152] protocol: add wl_output.{name,description} This is inspired from xdg-output-unstable-v1. This allows clients to get the name and description without having to use xdg_output. This should eventually allow us to restrict xdg_output to clients like Xwayland. The name is a unique non-persistent user-friendly string that can be used to refer to an output. This can be used by Wayland clients to refer to a specific wl_output (e.g. across processes or in CLI arguments). The description is a non-unique user-friendly string that can be displayed to the user. Signed-off-by: Simon Ser References: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/7 --- protocol/wayland.xml | 60 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 6001adcf..e3dab2e9 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2504,7 +2504,7 @@ - + An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an @@ -2568,7 +2568,7 @@ implementing a desktop-style output layout or those exposing virtual outputs, might fake this information. Instead of using x and y, clients should use xdg_output.logical_position. Instead of using make and model, - clients should use xdg_output.name and xdg_output.description. + clients should use name and description. @@ -2687,6 +2687,62 @@ use the output object anymore. + + + + + + Many compositors will assign user-friendly names to their outputs, show + them to the user, allow the user to refer to an output, etc. The client + may wish to know this name as well to offer the user similar behaviors. + + The name is a UTF-8 string with no convention defined for its contents. + Each name is unique among all wl_output globals. The name is only + guaranteed to be unique for the compositor instance. + + The same output name is used for all clients for a given wl_output + global. Thus, the name can be shared across processes to refer to a + specific wl_output global. + + The name is not guaranteed to be persistent across sessions, thus cannot + be used to reliably identify an output in e.g. configuration files. + + Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do + not assume that the name is a reflection of an underlying DRM connector, + X11 connection, etc. + + The name event is sent after binding the output object. This event is + only sent once per output object, and the name does not change over the + lifetime of the wl_output global. + + Compositors may re-use the same output name if the wl_output global is + destroyed and re-created later. Compositors should avoid re-using the + same name if possible. + + The name event will be followed by a done event. + + + + + + + Many compositors can produce human-readable descriptions of their + outputs. The client may wish to know this description as well, e.g. for + output selection purposes. + + The description is a UTF-8 string with no convention defined for its + contents. The description is not guaranteed to be unique among all + wl_output globals. Examples might include 'Foocorp 11" Display' or + 'Virtual X11 output via :1'. + + The description event is sent after binding the output object and + whenever the description changes. The description is optional, and may + not be sent at all. + + The description event will be followed by a done event. + + + From ca893075ef75f2ad4688d8fc1dcc20260f91afe9 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 24 Aug 2021 17:08:51 -0500 Subject: [PATCH 0777/1152] debug: Fix printing of new ids The client side closure traces have incorrect object ids for new server generated objects. This is because create_proxies() overwrites the id in 'n' type arguments by storing a pointer to the actual object in the 'o' field of the union. Getting back to an id from this pointer requires accessing a structure that isn't visible outside of wayland-client.c. Add a function pointer to fish the correct value out of the argument and pass it to wl_closure_print. Signed-off-by: Derek Foreman --- src/connection.c | 12 +++++++++--- src/wayland-client.c | 21 +++++++++++++++++---- src/wayland-private.h | 3 ++- src/wayland-server.c | 2 +- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/connection.c b/src/connection.c index ad16eeef..98f503b9 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1264,13 +1264,14 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) void wl_closure_print(struct wl_closure *closure, struct wl_object *target, - int send, int discarded) + int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg)) { int i; struct argument_details arg; const char *signature = closure->message->signature; struct timespec tp; unsigned int time; + uint32_t nval; clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); @@ -1322,12 +1323,17 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, fprintf(stderr, "nil"); break; case 'n': + if (n_parse) + nval = n_parse(&closure->args[i]); + else + nval = closure->args[i].n; + fprintf(stderr, "new id %s@", (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]"); - if (closure->args[i].n != 0) - fprintf(stderr, "%u", closure->args[i].n); + if (nval != 0) + fprintf(stderr, "%u", nval); else fprintf(stderr, "nil"); break; diff --git a/src/wayland-client.c b/src/wayland-client.c index 66f60e31..4fd7c90e 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -847,7 +847,7 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, } if (debug_client) - wl_closure_print(closure, &proxy->object, true, false); + wl_closure_print(closure, &proxy->object, true, false, NULL); if (wl_closure_send(closure, proxy->display->connection)) { wl_log("Error sending request: %s\n", strerror(errno)); @@ -1531,6 +1531,19 @@ queue_event(struct wl_display *display, int len) return size; } +static uint32_t +id_from_object(union wl_argument *arg) +{ + struct wl_proxy *proxy; + + if (arg->o) { + proxy = (struct wl_proxy *)arg->o; + return proxy->object.id; + } + + return 0; +} + static void dispatch_event(struct wl_display *display, struct wl_event_queue *queue) { @@ -1550,7 +1563,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); if (proxy_destroyed) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, true); + wl_closure_print(closure, &proxy->object, false, true, id_from_object); destroy_queued_closure(closure); return; } @@ -1559,13 +1572,13 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) if (proxy->dispatcher) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, false); + wl_closure_print(closure, &proxy->object, false, false, id_from_object); wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, false); + wl_closure_print(closure, &proxy->object, false, false, id_from_object); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); diff --git a/src/wayland-private.h b/src/wayland-private.h index 493e1bee..210451e4 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -211,7 +211,8 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); void wl_closure_print(struct wl_closure *closure, - struct wl_object *target, int send, int discarded); + struct wl_object *target, int send, int discarded, + uint32_t (*n_parse)(union wl_argument *arg)); void wl_closure_destroy(struct wl_closure *closure); diff --git a/src/wayland-server.c b/src/wayland-server.c index 6ae46891..02f1365c 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -156,7 +156,7 @@ log_closure(struct wl_resource *resource, struct wl_protocol_logger_message message; if (debug_server) - wl_closure_print(closure, object, send, false); + wl_closure_print(closure, object, send, false, NULL); if (!wl_list_empty(&display->protocol_loggers)) { message.resource = resource; From ebfc70cdf7c63082e2c9cccf47f0616a2e8969b0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 31 Oct 2021 12:10:08 +0100 Subject: [PATCH 0778/1152] protocol: wl_shm uses pre-multiplied alpha Add a note about pre-multiplied alpha for all wl_shm formats. Include an escape hatch in the spec to allow other protocol extensions to override this. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/61 --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index e3dab2e9..4e59c3a1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -296,6 +296,9 @@ The drm format codes match the macros defined in drm_fourcc.h, except argb8888 and xrgb8888. The formats actually supported by the compositor will be reported by the format event. + + For all wl_shm formats and unless specified in another protocol + extension, pre-multiplied alpha is used for pixel values. From 20fd3b3af974c8cb0b172a97d4f47ec9c5458566 Mon Sep 17 00:00:00 2001 From: Duncan McIntosh Date: Sat, 16 Oct 2021 20:28:34 -0400 Subject: [PATCH 0779/1152] wayland-shm: Check the size of sealed memory if ignoring SIGBUS handlers In 11623e8f, SIGBUS handlers aren't set if F_SEAL_SHRINK is configured on the memory. This helps avoid setting up handlers with cooperative clients; however, if an application gives an incorrect size, the compositor would access it anyways, figuring SIGBUS is impossible, and crash. This can be fixed by simply removing the seal-checking logic and always setting the signal handler. However, it seems that fstat can give the size of the memfd, so we can check that the size we were told is within the region. Since it's sealed to shrinking, it must never be shrunk in future, so we can really (hopefully) ignore SIGBUS. I was worried that fstat wasn't supported for this, but shm_overview(7) does mention that it is a possible use. The best solution would likely be avoiding SIGBUS entirely with MAP_NOSIGBUS, but that hasn't been merged yet and wouldn't help systems without it (e.g. with older kernels). A proof-of-concept of this crash is attached with the merge request. Running it with this patch gives an invalid-shm error, which is correct. Signed-off-by: Duncan McIntosh --- src/wayland-shm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 27d5b008..63ac0d7d 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -299,6 +300,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, uint32_t id, int fd, int32_t size) { struct wl_shm_pool *pool; + struct stat statbuf; int seals; int prot; int flags; @@ -320,7 +322,11 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, seals = fcntl(fd, F_GET_SEALS); if (seals == -1) seals = 0; - pool->sigbus_is_impossible = (seals & F_SEAL_SHRINK) ? true : false; + + if ((seals & F_SEAL_SHRINK) && fstat(fd, &statbuf) >= 0) + pool->sigbus_is_impossible = statbuf.st_size >= size; + else + pool->sigbus_is_impossible = false; #else pool->sigbus_is_impossible = false; #endif From 5420619f91e07d440f77db5ab0edf662a8d46479 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 4 Nov 2021 20:39:22 +0100 Subject: [PATCH 0780/1152] build: bump to version 1.19.91 for the alpha release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index acc3d787..0382a12f 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.19.90', + version: '1.19.91', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From 1638dad6137d7dd26a4a8c5d931bbb5c52dda46c Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Thu, 11 Nov 2021 19:47:14 -0500 Subject: [PATCH 0781/1152] protocol: sync wl_shm.format with libdrm 2.4.108 The four new formats added (all 16 bpc, RGB colorspace) are very useful for applications providing high bit depth content and rendering their buffers on CPU, as computations with 16 bit unsigned integers are often more efficient than with the (half float, 10 bit) alternative formats. Signed-off-by: Manuel Stoeckl --- protocol/wayland.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 4e59c3a1..89e6aab6 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -406,6 +406,10 @@ + + + + From 78590b3aff9c71407ff245c120b4d844e6b79c41 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Fri, 16 Jul 2021 13:35:37 +0200 Subject: [PATCH 0782/1152] protocol: clarify wl_data_offer::selection Clearly specify that switching focus within the same client doesn't mean a new selection will be send. Signed-off-by: Jan Grulich --- protocol/wayland.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 89e6aab6..784d9712 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -960,9 +960,10 @@ immediately before receiving keyboard focus and when a new selection is set while the client has keyboard focus. The data_offer is valid until a new data_offer or NULL is received - or until the client loses keyboard focus. The client must - destroy the previous selection data_offer, if any, upon receiving - this event. + or until the client loses keyboard focus. Switching surface with + keyboard focus within the same client doesn't mean a new selection + will be sent. The client must destroy the previous selection + data_offer, if any, upon receiving this event. From dcd8a62b183ce684f7c3b49bb5f59750fd2f1241 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 18 Nov 2021 16:30:09 +0100 Subject: [PATCH 0783/1152] build: bump to version 1.19.92 for the beta release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0382a12f..fb07b294 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.19.91', + version: '1.19.92', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From 28c2d8321b3ef9b206344f5eb911aeb5108703e8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Dec 2021 20:50:58 +0100 Subject: [PATCH 0784/1152] build: bump to version 1.19.93 for the RC1 release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index fb07b294..584c9f33 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.19.92', + version: '1.19.93', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From ba82e0d80617f720b133ecf3a251a53cca47a6f3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 8 Dec 2021 00:27:58 +0100 Subject: [PATCH 0785/1152] meson: override dependencies to ease use as subproject Make it easier to use Wayland as a Meson subproject by overriding dependencies we define. This allows to easily build Wayland as a subproject like so: subproject('wayland', required: false, default_options: ['documentation=false']) After this statement, the wayland-* dependencies will use the subproject instead of the system if available. Signed-off-by: Simon Ser --- cursor/meson.build | 9 +++++++++ egl/meson.build | 9 +++++++++ src/meson.build | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/cursor/meson.build b/cursor/meson.build index 5393a59f..f7d82e4e 100644 --- a/cursor/meson.build +++ b/cursor/meson.build @@ -36,3 +36,12 @@ pkgconfig.generate( libraries: wayland_cursor, filebase: 'wayland-cursor', ) + +wayland_cursor_dep = declare_dependency( + link_with: wayland_cursor, + include_directories: [ root_inc, include_directories('.') ], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('wayland-cursor', wayland_cursor_dep) +endif diff --git a/egl/meson.build b/egl/meson.build index 503ac953..065fd07b 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -41,3 +41,12 @@ pkgconfig.generate( description: 'Backend wayland-egl interface', version: '3' ) + +wayland_egl_dep = declare_dependency( + link_with: wayland_egl, + include_directories: [ root_inc, include_directories('.') ], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('wayland-egl', wayland_egl_dep) +endif diff --git a/src/meson.build b/src/meson.build index b76d4fee..ae8f3879 100644 --- a/src/meson.build +++ b/src/meson.build @@ -207,6 +207,10 @@ if get_option('libraries') ] ) + if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('wayland-server', wayland_server_dep) + endif + wayland_client = library( 'wayland-client', sources: [ @@ -251,6 +255,10 @@ if get_option('libraries') ] ) + if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('wayland-client', wayland_client_dep) + endif + install_headers([ 'wayland-util.h', 'wayland-server.h', From 75c1a93e2067220fa06208f20f8f096bb463ec08 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Dec 2021 17:20:36 +0100 Subject: [PATCH 0786/1152] build: bump to version 1.20.0 for the official release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 584c9f33..3bc25c97 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.19.93', + version: '1.20.0', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From 971a0a8b84b0891f0e4e56f25e4c5ae283e1a4c8 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Fri, 10 Dec 2021 12:44:44 +0100 Subject: [PATCH 0787/1152] doc: Clarify position of file descriptors in the stream The specification left the position and order of file descriptors unspecified. Specify that - order of file descriptors is maintained - position of file descriptors is bounded, but loose Signed-off-by: Mikhail Gusarov --- doc/publican/sources/Protocol.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 97e9ba29..0b27082d 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -194,6 +194,21 @@ + + The protocol does not specify the exact position of the ancillary data + in the stream, except that the order of file descriptors is the same as + the order of messages and fd arguments within messages on + the wire. + + + In particular, it means that any byte of the stream, even the message + header, may carry the ancillary data with file descriptors. + + + Clients and compositors should queue incoming data until they have + whole messages to process, as file descriptors may arrive earlier + or later than the corresponding data bytes. +
From eca836add596f5c00fd556613d510df81f0e23b2 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Sat, 18 Dec 2021 14:19:41 +0100 Subject: [PATCH 0788/1152] doc: Clarify that null terminator is included in string length Signed-off-by: Mikhail Gusarov --- doc/publican/sources/Protocol.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 0b27082d..580cecbc 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -149,9 +149,9 @@ string - Starts with an unsigned 32-bit length, followed by the - string contents, including terminating null byte, then padding - to a 32-bit boundary. + Starts with an unsigned 32-bit length (including null terminator), + followed by the string contents, including terminating null byte, + then padding to a 32-bit boundary. From 8893573651f16f1c3079c1bcbba7d82663c4f6a1 Mon Sep 17 00:00:00 2001 From: Max Ihlenfeldt Date: Wed, 15 Dec 2021 18:14:56 +0100 Subject: [PATCH 0789/1152] protocol: clarify wl_shm_pool.resize Add a note that the request only changes the size of the memory mapping and does not touch the mapped file. Signed-off-by: Max Ihlenfeldt --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 784d9712..2ba28438 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -258,6 +258,12 @@ for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. + + This request only changes the amount of bytes that are mmapped + by the server and does not touch the file corresponding to the + file descriptor passed at creation time. It is the client's + responsibility to ensure that the file is at least as big as + the new pool size. From ea237db7f66affd0ace847411ec2d7737fc79114 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 5 Jan 2022 16:20:49 -0600 Subject: [PATCH 0790/1152] tests: Fix tc_client_fd_leaks_exec test tc_client_fd_leaks and tc_client_fd_leaks_exec are currently the exact same test. It seems clear from the name that the latter was intended to spawn sanity_fd_leak_exec instead of sanity_fd_leak. Fixes #121 Signed-off-by: Derek Foreman --- tests/sanity-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 98beca8d..1a33c127 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -174,7 +174,7 @@ FAIL_TEST(tc_client_fd_leaks_exec) { struct display *d = display_create(); - client_create_noarg(d, sanity_fd_leak); + client_create_noarg(d, sanity_fd_leak_exec); display_run(d); test_disable_coredumps(); From aa6a07c2fe9c95843d9686b4f9a43f63ee67e071 Mon Sep 17 00:00:00 2001 From: shierote Date: Mon, 20 Dec 2021 21:25:23 +0900 Subject: [PATCH 0791/1152] doc: fix typo in wl_data_device.data_offer Signed-off-by: Taishi Eguchi --- protocol/wayland.xml | 2 +- tests/data/example-client.h | 2 +- tests/data/example.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 2ba28438..0cb07c64 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -896,7 +896,7 @@ which will subsequently be used in either the data_device.enter event (for drag-and-drop) or the data_device.selection event (for selections). Immediately - following the data_device_data_offer event, the new data_offer + following the data_device.data_offer event, the new data_offer object will send out data_offer.offer events to describe the mime types it offers. diff --git a/tests/data/example-client.h b/tests/data/example-client.h index 39d799c1..a14b5e00 100644 --- a/tests/data/example-client.h +++ b/tests/data/example-client.h @@ -2400,7 +2400,7 @@ struct wl_data_device_listener { * which will subsequently be used in either the data_device.enter * event (for drag-and-drop) or the data_device.selection event * (for selections). Immediately following the - * data_device_data_offer event, the new data_offer object will + * data_device.data_offer event, the new data_offer object will * send out data_offer.offer events to describe the mime types it * offers. * @param id the new data_offer object diff --git a/tests/data/example.xml b/tests/data/example.xml index 38feec30..2d769408 100644 --- a/tests/data/example.xml +++ b/tests/data/example.xml @@ -812,7 +812,7 @@ which will subsequently be used in either the data_device.enter event (for drag-and-drop) or the data_device.selection event (for selections). Immediately - following the data_device_data_offer event, the new data_offer + following the data_device.data_offer event, the new data_offer object will send out data_offer.offer events to describe the mime types it offers. From 31b17e3d8533739970bdc8692b749af41c5d24af Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 10 Jan 2022 11:12:39 +0100 Subject: [PATCH 0792/1152] build: re-open main branch for regular development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3bc25c97..07bbd293 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.20.0', + version: '1.20.90', license: 'MIT', meson_version: '>= 0.52.1', default_options: [ From 65616e946b547bc2b20ca004662447fbadf990e3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 10 Jan 2022 14:50:05 +0100 Subject: [PATCH 0793/1152] tests: use __typeof__ instead of typeof typeof is a GNU extension. Compiler extensions should be prefixed with __ per the C standard. Signed-off-by: Simon Ser --- tests/os-wrappers-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index aadb93bc..8d8c3ab9 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -70,7 +70,7 @@ static int fall_back; #define REAL(func) (__interceptor_ ## func) ? \ __interceptor_ ## func : \ - (typeof(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func) + (__typeof__(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func) DECL(int, socket, int, int, int); DECL(int, fcntl, int, int, ...); From 0d314c4a04ef1b86a1ea66107b2d1a8d1bcd93b9 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 10 Jan 2022 14:51:55 +0100 Subject: [PATCH 0794/1152] build: don't rely on implicit GNU extensions Currently libwayland assumes GNU extensions will be available, but doesn't define the C standard to use. Instead, let's unconditionally enable POSIX extensions, and enable GNU extensions on a case-by-case basis as needed. Signed-off-by: Simon Ser --- cursor/xcursor.c | 1 + meson.build | 10 ++++++++-- tests/display-test.c | 1 + tests/event-loop-test.c | 1 + tests/fixed-test.c | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 0506680f..188be7c8 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -23,6 +23,7 @@ * SOFTWARE. */ +#define _GNU_SOURCE #include "xcursor.h" #include #include diff --git a/meson.build b/meson.build index 07bbd293..cab267e9 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,12 @@ config_h = configuration_data() config_h.set_quoted('PACKAGE', meson.project_name()) config_h.set_quoted('PACKAGE_VERSION', meson.project_version()) +cc_args = [] +if host_machine.system() != 'freebsd' + cc_args += ['-D_POSIX_C_SOURCE=200809L'] +endif +add_project_arguments(cc_args, language: 'c') + compiler_flags = [ '-Wno-unused-parameter', '-Wstrict-prototypes', @@ -79,7 +85,7 @@ if get_option('libraries') ] foreach d: decls - if not cc.has_header_symbol(d['header'], d['symbol'], dependencies: epoll_dep) + if not cc.has_header_symbol(d['header'], d['symbol'], dependencies: epoll_dep, args: cc_args) error('@0@ is needed to compile Wayland libraries'.format(d['symbol'])) endif endforeach @@ -87,7 +93,7 @@ if get_option('libraries') rt_dep = [] if not cc.has_function('clock_gettime', prefix: '#include ') rt_dep = cc.find_library('rt') - if not cc.has_function('clock_gettime', prefix: '#include ', dependencies: rt_dep) + if not cc.has_function('clock_gettime', prefix: '#include ', dependencies: rt_dep, args: cc_args) error('clock_gettime not found') endif endif diff --git a/tests/display-test.c b/tests/display-test.c index 763adc91..a6f410da 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -24,6 +24,7 @@ * SOFTWARE. */ +#define _GNU_SOURCE #include #include #include diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index 9d43c912..a51ba8fb 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -24,6 +24,7 @@ * SOFTWARE. */ +#define _GNU_SOURCE #include #include #include diff --git a/tests/fixed-test.c b/tests/fixed-test.c index 47a4dae8..0b587978 100644 --- a/tests/fixed-test.c +++ b/tests/fixed-test.c @@ -23,6 +23,7 @@ * SOFTWARE. */ +#define _GNU_SOURCE #include #include #include From 40c275f642e3895aeb748403fcdfd92d7d875d65 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 10 Jan 2022 14:54:02 +0100 Subject: [PATCH 0795/1152] build: set c_std=c99 Set explicitly the C standard to use to make sure we don't use features not available on our target platforms. Signed-off-by: Simon Ser --- meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cab267e9..e9691ffe 100644 --- a/meson.build +++ b/meson.build @@ -5,7 +5,8 @@ project( meson_version: '>= 0.52.1', default_options: [ 'warning_level=2', - 'buildtype=debugoptimized' + 'buildtype=debugoptimized', + 'c_std=c99', ] ) wayland_version = meson.project_version().split('.') From ee92898cb5fbf2d34aed7d593cbc8966b1b563de Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 10 Jan 2022 17:31:07 +0100 Subject: [PATCH 0796/1152] protocol: xkb_v1 is null-terminated Closes #270 Signed-off-by: Julian Orth --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 0cb07c64..bb31bc9f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2261,7 +2261,7 @@ + summary="libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode"/> From 4b05ecb8f7506e4e4d62532a0a3500c2b5711b38 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Feb 2022 15:04:42 +0100 Subject: [PATCH 0797/1152] build: explicitly set check arg in run_command() Fixes the following warning: WARNING: You should add the boolean check kwarg to the run_command call. It currently defaults to false, but it will default to true in future releases of meson. See also: https://github.com/mesonbuild/meson/issues/9300 Signed-off-by: Simon Ser --- doc/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/meson.build b/doc/meson.build index f74b6b1b..57c71802 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -18,7 +18,7 @@ if vers.version_compare('< 2.26.0') endif manpage_xsl = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl' -cmd = run_command(xsltproc, '--nonet', manpage_xsl) +cmd = run_command(xsltproc, '--nonet', manpage_xsl, check: false) if cmd.returncode() != 0 error('The style sheet for man pages providing "@0@" was not found.'.format(manpage_xsl)) endif From 5eb5620cbd317aac4a61e357c3c92bd889d6079b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 31 Jan 2022 22:23:30 +0100 Subject: [PATCH 0798/1152] Use zalloc for structs When allocating memory for structs, use zalloc instead of malloc. This ensures the memory is zero-initialized, and reduces the risk of forgetting to initialize all struct fields. Signed-off-by: Simon Ser --- src/connection.c | 4 ++-- src/event-loop.c | 10 +++++----- src/wayland-client.c | 2 +- src/wayland-server.c | 8 ++++---- src/wayland-shm.c | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/connection.c b/src/connection.c index 98f503b9..8c51a24e 100644 --- a/src/connection.c +++ b/src/connection.c @@ -568,10 +568,10 @@ wl_closure_init(const struct wl_message *message, uint32_t size, if (size) { *num_arrays = wl_message_count_arrays(message); - closure = malloc(sizeof *closure + size + + closure = zalloc(sizeof *closure + size + *num_arrays * sizeof(struct wl_array)); } else { - closure = malloc(sizeof *closure); + closure = zalloc(sizeof *closure); } if (!closure) { diff --git a/src/event-loop.c b/src/event-loop.c index c7c98b08..37cf95d3 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -179,7 +179,7 @@ wl_event_loop_add_fd(struct wl_event_loop *loop, { struct wl_event_source_fd *source; - source = malloc(sizeof *source); + source = zalloc(sizeof *source); if (source == NULL) return NULL; @@ -568,7 +568,7 @@ wl_event_loop_add_timer(struct wl_event_loop *loop, if (wl_timer_heap_ensure_timerfd(&loop->timers) < 0) return NULL; - source = malloc(sizeof *source); + source = zalloc(sizeof *source); if (source == NULL) return NULL; @@ -718,7 +718,7 @@ wl_event_loop_add_signal(struct wl_event_loop *loop, struct wl_event_source_signal *source; sigset_t mask; - source = malloc(sizeof *source); + source = zalloc(sizeof *source); if (source == NULL) return NULL; @@ -775,7 +775,7 @@ wl_event_loop_add_idle(struct wl_event_loop *loop, { struct wl_event_source_idle *source; - source = malloc(sizeof *source); + source = zalloc(sizeof *source); if (source == NULL) return NULL; @@ -885,7 +885,7 @@ wl_event_loop_create(void) { struct wl_event_loop *loop; - loop = malloc(sizeof *loop); + loop = zalloc(sizeof *loop); if (loop == NULL) return NULL; diff --git a/src/wayland-client.c b/src/wayland-client.c index 4fd7c90e..6b0cf431 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -343,7 +343,7 @@ wl_display_create_queue(struct wl_display *display) { struct wl_event_queue *queue; - queue = malloc(sizeof *queue); + queue = zalloc(sizeof *queue); if (queue == NULL) return NULL; diff --git a/src/wayland-server.c b/src/wayland-server.c index 02f1365c..5edbc9cd 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1062,7 +1062,7 @@ wl_display_create(void) if (debug && (strstr(debug, "server") || strstr(debug, "1"))) debug_server = 1; - display = malloc(sizeof *display); + display = zalloc(sizeof *display); if (display == NULL) return NULL; @@ -1238,7 +1238,7 @@ wl_global_create(struct wl_display *display, return NULL; } - global = malloc(sizeof *global); + global = zalloc(sizeof *global); if (global == NULL) return NULL; @@ -1822,7 +1822,7 @@ wl_resource_create(struct wl_client *client, { struct wl_resource *resource; - resource = malloc(sizeof *resource); + resource = zalloc(sizeof *resource); if (resource == NULL) return NULL; @@ -1888,7 +1888,7 @@ wl_display_add_protocol_logger(struct wl_display *display, { struct wl_protocol_logger *logger; - logger = malloc(sizeof *logger); + logger = zalloc(sizeof *logger); if (!logger) return NULL; diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 63ac0d7d..28c550dd 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -223,7 +223,7 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, return; } - buffer = malloc(sizeof *buffer); + buffer = zalloc(sizeof *buffer); if (buffer == NULL) { wl_client_post_no_memory(client); return; @@ -312,7 +312,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, goto err_close; } - pool = malloc(sizeof *pool); + pool = zalloc(sizeof *pool); if (pool == NULL) { wl_client_post_no_memory(client); goto err_close; From e949b3bfbb92363724ef1bd5b2f5736de8a9f98a Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Wed, 15 Dec 2021 10:31:41 +1100 Subject: [PATCH 0799/1152] display-test: Fix a race condition in test suite Several tests in this suite use setting and checking client.display_stopped (in test-compositor.h) to synchronise between threads. This is a data race because display_stopped is a non-atomic int. Fix this by making it an atomic_bool instead. We don't need to change the access code because reads and writes are sequentially consistent by default. This can be reproduced (with both clang and gcc) by running ``` meson -Db_sanitize=thread build cd build ninja meson test ``` Signed-off-by: Fergus Dall --- tests/test-compositor.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test-compositor.h b/tests/test-compositor.h index f763fef3..7b350fe9 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -25,6 +25,7 @@ #include #include +#include #include "wayland-server.h" #include "wayland-client.h" @@ -65,7 +66,7 @@ struct client { struct wl_display *wl_display; struct test_compositor *tc; - int display_stopped; + atomic_bool display_stopped; }; struct client *client_connect(void); From 4ebd997de2b52c0998a91436ed05ffbe6d56a306 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Thu, 27 Jan 2022 21:11:20 +0200 Subject: [PATCH 0800/1152] cursor: Remove unused XcursorLibraryLoadImages() function XcursorLibraryLoadImages() function is unused and not exported according to objdump, so its removal should be an ABI compatible change. Signed-off-by: Vlad Zahorodnii --- cursor/xcursor.c | 77 ------------------------------------------------ cursor/xcursor.h | 3 -- 2 files changed, 80 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 188be7c8..744bbcd9 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -822,83 +822,6 @@ _XcursorThemeInherits (const char *full) return result; } -static FILE * -XcursorScanTheme (const char *theme, const char *name) -{ - FILE *f = NULL; - char *full; - char *dir; - const char *path; - char *inherits = NULL; - const char *i; - char *xcursor_path; - - if (!theme || !name) - return NULL; - - /* - * Scan this theme - */ - xcursor_path = XcursorLibraryPath (); - for (path = xcursor_path; - path && f == NULL; - path = _XcursorNextPath (path)) - { - dir = _XcursorBuildThemeDir (path, theme); - if (dir) - { - full = _XcursorBuildFullname (dir, "cursors", name); - if (full) - { - f = fopen (full, "r"); - free (full); - } - if (!f && !inherits) - { - full = _XcursorBuildFullname (dir, "", "index.theme"); - if (full) - { - inherits = _XcursorThemeInherits (full); - free (full); - } - } - free (dir); - } - } - /* - * Recurse to scan inherited themes - */ - for (i = inherits; i && f == NULL; i = _XcursorNextPath (i)) - f = XcursorScanTheme (i, name); - if (inherits != NULL) - free (inherits); - free (xcursor_path); - return f; -} - -XcursorImages * -XcursorLibraryLoadImages (const char *file, const char *theme, int size) -{ - FILE *f = NULL; - XcursorImages *images = NULL; - - if (!file) - return NULL; - - if (theme) - f = XcursorScanTheme (theme, file); - if (!f) - f = XcursorScanTheme ("default", file); - if (f) - { - images = XcursorFileLoadImages (f, size); - if (images) - XcursorImagesSetName (images, file); - fclose (f); - } - return images; -} - static void load_all_cursors_from_dir(const char *path, int size, void (*load_callback)(XcursorImages *, void *), diff --git a/cursor/xcursor.h b/cursor/xcursor.h index c1ca12c1..fe2339a4 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -54,9 +54,6 @@ typedef struct _XcursorImages { char *name; /* name used to load images */ } XcursorImages; -XcursorImages * -XcursorLibraryLoadImages (const char *file, const char *theme, int size); - void XcursorImagesDestroy (XcursorImages *images); From c78807520f6c458f3afda3c709fb0f4862971958 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 5 Jan 2021 12:10:58 +0100 Subject: [PATCH 0801/1152] meson: build requirement to 0.56.0 meson.project_build_root() is only available with 0.56.0. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f70e1fd..db5c9c30 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -74,10 +74,10 @@ stages: BUILD_OS: debian FDO_DISTRIBUTION_VERSION: buster FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' - FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.52.1' + FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.56.0' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2021-08-03.0" + FDO_DISTRIBUTION_TAG: "2022-02-05.0" .debian-x86_64: extends: diff --git a/meson.build b/meson.build index e9691ffe..e7fc3eef 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'wayland', 'c', version: '1.20.90', license: 'MIT', - meson_version: '>= 0.52.1', + meson_version: '>= 0.56.0', default_options: [ 'warning_level=2', 'buildtype=debugoptimized', From 7816f0b84218dbfa63689052c0a996600902cd8e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 5 Jan 2021 12:05:11 +0100 Subject: [PATCH 0802/1152] meson: use project build root for doxygen output meson.build_root() returns the parent's build directory if Wayland is a subproject. This fails with: error: tag OUTPUT_DIRECTORY: Output directory '/doc/doxygen' does not exist and cannot be created Instead, use meson.project_build_root(), which returns the subproject's build directory. Signed-off-by: Simon Ser --- doc/doxygen/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build index f2bee147..9f27ba82 100644 --- a/doc/doxygen/meson.build +++ b/doc/doxygen/meson.build @@ -13,7 +13,7 @@ dot_map = [] doxygen_conf = configuration_data() doxygen_conf.set('VERSION', meson.project_version()) -doxygen_conf.set('top_builddir', meson.build_root()) +doxygen_conf.set('top_builddir', meson.project_build_root()) wayland_doxygen = configure_file( input: 'wayland.doxygen.in', output: 'wayland.doxygen', From d690712b7b83faeb8fca4015b296aece2fb30c65 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 5 Jan 2021 12:07:13 +0100 Subject: [PATCH 0803/1152] meson: use absolute paths for doxygen stamp files The relative paths are incorrect when running as a subproject. Signed-off-by: Simon Ser --- doc/doxygen/meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build index 9f27ba82..61126206 100644 --- a/doc/doxygen/meson.build +++ b/doc/doxygen/meson.build @@ -76,6 +76,7 @@ foreach f_name, sections: formats # We do not really need an output file, but Meson # will complain if one is not set, so we use a # dummy 'stamp' file + stamp = join_paths(meson.current_build_dir(), '@0@.stamp'.format(t_name)) custom_target( t_name, command: [ @@ -84,7 +85,7 @@ foreach f_name, sections: formats '--builddir=@OUTDIR@', '--section=@0@'.format(s_name), '--output-format=@0@'.format(f_name), - '--stamp=doc/doxygen/@0@.stamp'.format(t_name), + '--stamp=@0@'.format(stamp), wayland_doxygen, '@INPUT@', ], @@ -97,13 +98,14 @@ foreach f_name, sections: formats endforeach man_files = shared_files + server_files + client_files + cursor_files +stamp = join_paths(meson.current_build_dir(), 'man3.stamp') custom_target( 'man-pages-3', command: [ gen_doxygen, '--builddir=@OUTDIR@', '--output-format=man3', - '--stamp=doc/doxygen/man3.stamp', + '--stamp=@0@'.format(stamp), wayland_doxygen, '@INPUT@', ], From af8b5c07826ed2f2624cf87c0e2da4f8e9089ee0 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Sun, 20 Feb 2022 20:10:49 +0100 Subject: [PATCH 0804/1152] protocol: wl_shm.format events are actually sent after bind Protocol documentation mistakenly specified that wl_shm.format events are sent at connection setup time, but that's impossible (clients do not yet know ID of wl_shm object at the time) and contradicts implementation in libwayland. Signed-off-by: Mikhail Gusarov --- protocol/wayland.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index bb31bc9f..92e2432a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -277,8 +277,8 @@ Clients can create wl_shm_pool objects using the create_pool request. - At connection setup time, the wl_shm object emits one or more - format events to inform clients about the valid pixel formats + On binding the wl_shm object one or more format events + are emitted to inform clients about the valid pixel formats that can be used for buffers. From ca4678354c4a7c21bfd184e604ad7a3c8224e10c Mon Sep 17 00:00:00 2001 From: Alexander Irion Date: Mon, 7 Mar 2022 15:49:49 +0100 Subject: [PATCH 0805/1152] connection: Make wl_closure_print output atomic When multiple threads are used, output from different threads was intermixed in one line. That what breaking parsing of the log messages. Now, intermixing is prevented by using a memstream. Signed-off-by: Alexander Irion --- src/connection.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/connection.c b/src/connection.c index 8c51a24e..a2d1b2f2 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1272,11 +1272,18 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, struct timespec tp; unsigned int time; uint32_t nval; + FILE *f; + char *buffer; + size_t buffer_length; + + f = open_memstream(&buffer, &buffer_length); + if (f == NULL) + return; clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(stderr, "[%7u.%03u] %s%s%s@%u.%s(", + fprintf(f, "[%7u.%03u] %s%s%s@%u.%s(", time / 1000, time % 1000, discarded ? "discarded " : "", send ? " -> " : "", @@ -1286,41 +1293,41 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); if (i > 0) - fprintf(stderr, ", "); + fprintf(f, ", "); switch (arg.type) { case 'u': - fprintf(stderr, "%u", closure->args[i].u); + fprintf(f, "%u", closure->args[i].u); break; case 'i': - fprintf(stderr, "%d", closure->args[i].i); + fprintf(f, "%d", closure->args[i].i); break; case 'f': /* The magic number 390625 is 1e8 / 256 */ if (closure->args[i].f >= 0) { - fprintf(stderr, "%d.%08d", + fprintf(f, "%d.%08d", closure->args[i].f / 256, 390625 * (closure->args[i].f % 256)); } else { - fprintf(stderr, "-%d.%08d", + fprintf(f, "-%d.%08d", closure->args[i].f / -256, -390625 * (closure->args[i].f % 256)); } break; case 's': if (closure->args[i].s) - fprintf(stderr, "\"%s\"", closure->args[i].s); + fprintf(f, "\"%s\"", closure->args[i].s); else - fprintf(stderr, "nil"); + fprintf(f, "nil"); break; case 'o': if (closure->args[i].o) - fprintf(stderr, "%s@%u", + fprintf(f, "%s@%u", closure->args[i].o->interface->name, closure->args[i].o->id); else - fprintf(stderr, "nil"); + fprintf(f, "nil"); break; case 'n': if (n_parse) @@ -1328,25 +1335,30 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, else nval = closure->args[i].n; - fprintf(stderr, "new id %s@", + fprintf(f, "new id %s@", (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]"); if (nval != 0) - fprintf(stderr, "%u", nval); + fprintf(f, "%u", nval); else - fprintf(stderr, "nil"); + fprintf(f, "nil"); break; case 'a': - fprintf(stderr, "array[%zu]", closure->args[i].a->size); + fprintf(f, "array[%zu]", closure->args[i].a->size); break; case 'h': - fprintf(stderr, "fd %d", closure->args[i].h); + fprintf(f, "fd %d", closure->args[i].h); break; } } - fprintf(stderr, ")\n"); + fprintf(f, ")\n"); + + if (fclose(f) == 0) { + fprintf(stderr, "%s", buffer); + free(buffer); + } } static int From 02661fde24b726edea201e2d4c2382b2723303cd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Mar 2022 13:56:32 +0100 Subject: [PATCH 0806/1152] build: use full_path() instead of path() Fixes the following warning: WARNING: Project targeting '>= 0.56.0' but tried to use feature deprecated since '0.55.0': ExternalProgram.path. use ExternalProgram.full_path() instead Signed-off-by: Simon Ser --- egl/meson.build | 2 +- tests/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/egl/meson.build b/egl/meson.build index 065fd07b..b3cbdf31 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -11,7 +11,7 @@ wayland_egl = library( executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') -nm_path = find_program('nm').path() +nm_path = find_program('nm').full_path() test( 'wayland-egl symbols check', diff --git a/tests/meson.build b/tests/meson.build index 58794e7d..dd1aa850 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -77,7 +77,7 @@ if add_languages('cpp') ) endif -sed_path = find_program('sed').path() +sed_path = find_program('sed').full_path() if get_option('scanner') test( From 24e0a7b622d3f0e5fac043cb90e0e95093b650d5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Mar 2022 13:57:23 +0100 Subject: [PATCH 0807/1152] build: specify native arg in add_languages() Fixes the following warning: WARNING: add_languages is missing native:, assuming languages are wanted for both host and build. Signed-off-by: Simon Ser --- tests/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/meson.build b/tests/meson.build index dd1aa850..ffb5136c 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -65,7 +65,7 @@ executable( dependencies: test_runner_dep ) -if add_languages('cpp') +if add_languages('cpp', native: false) test( 'cpp-compile-test', executable( From b6bbc0c44dd1d533700a973b3837410d4a9df7c7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Mar 2022 13:58:17 +0100 Subject: [PATCH 0808/1152] build: use get_variable(pkgconfig) instead of get_pkgconfig_variable() We don't get a warning for it yet, but get_pkgconfig_variable() is deprecated. Signed-off-by: Simon Ser --- src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index ae8f3879..266c8b1e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -71,7 +71,7 @@ endif if meson.is_cross_build() or not get_option('scanner') scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version()) - wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) + wayland_scanner_for_build = find_program(scanner_dep.get_variable(pkgconfig: 'wayland_scanner')) else wayland_scanner_for_build = wayland_scanner endif From ae263cca3e848cb2c67a28a690bd5e5d6968faae Mon Sep 17 00:00:00 2001 From: Aleksandr Mezin Date: Wed, 26 Jan 2022 19:16:55 +0600 Subject: [PATCH 0809/1152] util: always check result of wl_array_add() Not checking the result of wl_array_add() can cause writes past the end of the allocated buffer if realloc fails. Signed-off-by: Aleksandr Mezin --- src/wayland-util.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index c89a67bd..68116bf9 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -241,8 +241,10 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) if (count < i) return -1; - if (count == i) - wl_array_add(entries, sizeof *start); + if (count == i) { + if (!wl_array_add(entries, sizeof *start)) + return -1; + } start = entries->data; start[i].data = data; @@ -277,7 +279,9 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) return -1; if (count == i) { - wl_array_add(entries, sizeof *start); + if (!wl_array_add(entries, sizeof *start)) + return -1; + start = entries->data; start[i].data = NULL; } else { From 03e8a1f84b6a15c9531db1ca8d0a25f9fcffaf25 Mon Sep 17 00:00:00 2001 From: Aleksandr Mezin Date: Wed, 9 Feb 2022 04:10:42 +0600 Subject: [PATCH 0810/1152] util: set errno in wl_map_reserve_new() And also fix wl_connection_demarshal() to pass through that errno. Signed-off-by: Aleksandr Mezin --- src/connection.c | 10 ++++++---- src/wayland-util.c | 14 +++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/connection.c b/src/connection.c index a2d1b2f2..3a4ab478 100644 --- a/src/connection.c +++ b/src/connection.c @@ -810,10 +810,12 @@ wl_connection_demarshal(struct wl_connection *connection, } if (wl_map_reserve_new(objects, id) < 0) { - wl_log("not a valid new object id (%u), " - "message %s(%s)\n", - id, message->name, message->signature); - errno = EINVAL; + if (errno == EINVAL) { + wl_log("not a valid new object id (%u), " + "message %s(%s)\n", id, + message->name, + message->signature); + } goto err; } diff --git a/src/wayland-util.c b/src/wayland-util.c index 68116bf9..ee74bc12 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -24,6 +24,7 @@ * SOFTWARE. */ +#include #include #include #include @@ -261,13 +262,17 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) struct wl_array *entries; if (i < WL_SERVER_ID_START) { - if (map->side == WL_MAP_CLIENT_SIDE) + if (map->side == WL_MAP_CLIENT_SIDE) { + errno = EINVAL; return -1; + } entries = &map->client_entries; } else { - if (map->side == WL_MAP_SERVER_SIDE) + if (map->side == WL_MAP_SERVER_SIDE) { + errno = EINVAL; return -1; + } entries = &map->server_entries; i -= WL_SERVER_ID_START; @@ -275,8 +280,10 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) count = entries->size / sizeof *start; - if (count < i) + if (count < i) { + errno = EINVAL; return -1; + } if (count == i) { if (!wl_array_add(entries, sizeof *start)) @@ -287,6 +294,7 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) } else { start = entries->data; if (start[i].data != NULL) { + errno = EINVAL; return -1; } } From 884d5fe3abc98c8b97f71974752ff9f9a3056e8e Mon Sep 17 00:00:00 2001 From: Aleksandr Mezin Date: Wed, 9 Feb 2022 05:36:11 +0600 Subject: [PATCH 0811/1152] util: set errno in wl_map_insert_at() And add errno checks in callers, where it seems to be necessary. Signed-off-by: Aleksandr Mezin --- src/wayland-client.c | 5 ++++- src/wayland-server.c | 18 +++++++++++------- src/wayland-util.c | 4 +++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 6b0cf431..a9fb01e8 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -485,7 +485,10 @@ wl_proxy_create_for_id(struct wl_proxy *factory, proxy->refcount = 1; proxy->version = factory->version; - wl_map_insert_at(&display->objects, 0, id, proxy); + if (wl_map_insert_at(&display->objects, 0, id, proxy) == -1) { + free(proxy); + return NULL; + } return proxy; } diff --git a/src/wayland-server.c b/src/wayland-server.c index 5edbc9cd..9fc337be 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1843,9 +1843,11 @@ wl_resource_create(struct wl_client *client, resource->dispatcher = NULL; if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) { - wl_resource_post_error(client->display_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid new id %d", id); + if (errno == EINVAL) { + wl_resource_post_error(client->display_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid new id %d", id); + } free(resource); return NULL; } @@ -2240,10 +2242,12 @@ wl_client_add_resource(struct wl_client *client, WL_MAP_ENTRY_LEGACY, resource); } else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY, resource->object.id, resource) < 0) { - wl_resource_post_error(client->display_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid new id %d", - resource->object.id); + if (errno == EINVAL) { + wl_resource_post_error(client->display_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid new id %d", + resource->object.id); + } return 0; } diff --git a/src/wayland-util.c b/src/wayland-util.c index ee74bc12..e82b7d26 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -239,8 +239,10 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) } count = entries->size / sizeof *start; - if (count < i) + if (count < i) { + errno = EINVAL; return -1; + } if (count == i) { if (!wl_array_add(entries, sizeof *start)) From 79c84ed3f132fd6bc01c2f62a8477d8d1a462b67 Mon Sep 17 00:00:00 2001 From: Aleksandr Mezin Date: Wed, 9 Feb 2022 06:26:18 +0600 Subject: [PATCH 0812/1152] client, server: handle wl_map_insert_new() failures Signed-off-by: Aleksandr Mezin --- src/wayland-client.c | 13 +++++++++++-- src/wayland-server.c | 9 ++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index a9fb01e8..75692e6e 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -430,6 +430,10 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, proxy->version = version; proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy); + if (proxy->object.id == 0) { + free(proxy); + return NULL; + } return proxy; } @@ -1158,11 +1162,16 @@ wl_display_connect_to_fd(int fd) pthread_cond_init(&display->reader_cond, NULL); display->reader_count = 0; - wl_map_insert_new(&display->objects, 0, NULL); + if (wl_map_insert_at(&display->objects, 0, 0, NULL) == -1) + goto err_connection; - display->proxy.object.interface = &wl_display_interface; display->proxy.object.id = wl_map_insert_new(&display->objects, 0, display); + + if (display->proxy.object.id == 0) + goto err_connection; + + display->proxy.object.interface = &wl_display_interface; display->proxy.display = display; display->proxy.object.implementation = (void(**)(void)) &display_listener; display->proxy.user_data = display; diff --git a/src/wayland-server.c b/src/wayland-server.c index 9fc337be..a5034527 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1826,8 +1826,13 @@ wl_resource_create(struct wl_client *client, if (resource == NULL) return NULL; - if (id == 0) + if (id == 0) { id = wl_map_insert_new(&client->objects, 0, NULL); + if (id == 0) { + free(resource); + return NULL; + } + } resource->object.id = id; resource->object.interface = interface; @@ -2240,6 +2245,8 @@ wl_client_add_resource(struct wl_client *client, resource->object.id = wl_map_insert_new(&client->objects, WL_MAP_ENTRY_LEGACY, resource); + if (resource->object.id == 0) + return 0; } else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY, resource->object.id, resource) < 0) { if (errno == EINVAL) { From 868eb99eb07965f34461693d82c68dba503aec46 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 31 Mar 2020 13:47:04 +1000 Subject: [PATCH 0813/1152] protocol: add the wl_pointer.axis_value120 events These events are for high-resolution wheels. Each logical wheel click represents an axis value120 value of 120, fractions of a wheel click an integer fraction thereof. The new event replaces wl_pointer.axis_discrete for wl_pointer versions 8 and above. Signed-off-by: Peter Hutterer --- protocol/wayland.xml | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 92e2432a..4389262a 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1787,7 +1787,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -1920,7 +1920,7 @@ - + The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -2220,6 +2220,9 @@ This event carries the axis value of the wl_pointer.axis event in discrete steps (e.g. mouse wheel clicks). + This event is deprecated with wl_pointer version 8 - this event is not + sent to clients supporting version 8 or later. + This event does not occur on its own, it is coupled with a wl_pointer.axis event that represents this axis value on a continuous scale. The protocol guarantees that each axis_discrete @@ -2245,9 +2248,37 @@ + + + + Discrete high-resolution scroll information. + + This event carries high-resolution wheel scroll information, + with each multiple of 120 representing one logical scroll step + (a wheel detent). For example, an axis_value120 of 30 is one quarter of + a logical scroll step in the positive direction, a value120 of + -240 are two logical scroll steps in the negative direction within the + same hardware event. + Clients that rely on discrete scrolling should accumulate the + value120 to multiples of 120 before processing the event. + + The value120 must not be zero. + + This event replaces the wl_pointer.axis_discrete event in clients + supporting wl_pointer version 8 or later. + + Where a wl_pointer.axis_source event occurs in the same + wl_pointer.frame, the axis source applies to this event. + + The order of wl_pointer.axis_value120 and wl_pointer.axis_source is + not guaranteed. + + + + - + The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -2374,7 +2405,7 @@ - + The wl_touch interface represents a touchscreen associated with a seat. From 962aefda42f7bbfb6d9b64b7b177e232213d8a59 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 31 Jan 2022 23:09:26 +0100 Subject: [PATCH 0814/1152] server: introduce wl_signal_emit_mutable wl_signal_emit doesn't handle well situations where a listener removes another listener. This can happen in practice: wlroots and Weston [1] both have private helpers to workaround this defect. wl_signal_emit can't be fixed without breaking the API. Instead, introduce a new function. Callers need to make sure to always remove listeners when they are free'd. [1]: https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/457 Signed-off-by: Simon Ser Signed-off-by: Alexandros Frantzis --- src/wayland-server-core.h | 3 ++ src/wayland-server.c | 63 +++++++++++++++++++++++++++++++++++++++ tests/signal-test.c | 41 +++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index cbc70c09..ab5b4487 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -481,6 +481,9 @@ wl_signal_emit(struct wl_signal *signal, void *data) l->notify(l, data); } +void +wl_signal_emit_mutable(struct wl_signal *signal, void *data); + typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource); /* diff --git a/src/wayland-server.c b/src/wayland-server.c index a5034527..71b03606 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -2096,6 +2096,69 @@ wl_client_for_each_resource(struct wl_client *client, wl_map_for_each(&client->objects, resource_iterator_helper, &context); } +static void +handle_noop(struct wl_listener *listener, void *data) +{ + /* Do nothing */ +} + +/** Emits this signal, notifying all registered listeners. + * + * A safer version of wl_signal_emit() which can gracefully handle additions + * and deletions of any signal listener from within listener notification + * callbacks. + * + * Listeners deleted during a signal emission and which have not already been + * notified at the time of deletion are not notified by that emission. + * + * Listeners added (or readded) during signal emission are ignored by that + * emission. + * + * Note that repurposing a listener without explicitly removing it and readding + * it is not supported and can lead to unexpected behavior. + * + * \param signal The signal object that will emit the signal + * \param data The data that will be emitted with the signal + * + * \memberof wl_signal + * \since 1.20.90 + */ +WL_EXPORT void +wl_signal_emit_mutable(struct wl_signal *signal, void *data) +{ + struct wl_listener cursor; + struct wl_listener end; + + /* Add two special markers: one cursor and one end marker. This way, we + * know that we've already called listeners on the left of the cursor + * and that we don't want to call listeners on the right of the end + * marker. The 'it' function can remove any element it wants from the + * list without troubles. + * + * There was a previous attempt that used to steal the whole list of + * listeners but then that broke wl_signal_get(). + * + * wl_list_for_each_safe tries to be safe but it fails: it works fine + * if the current item is removed, but not if the next one is. */ + wl_list_insert(&signal->listener_list, &cursor.link); + cursor.notify = handle_noop; + wl_list_insert(signal->listener_list.prev, &end.link); + end.notify = handle_noop; + + while (cursor.link.next != &end.link) { + struct wl_list *pos = cursor.link.next; + struct wl_listener *l = wl_container_of(pos, l, link); + + wl_list_remove(&cursor.link); + wl_list_insert(pos, &cursor.link); + + l->notify(l, data); + } + + wl_list_remove(&cursor.link); + wl_list_remove(&end.link); +} + /** \cond INTERNAL */ /** Initialize a wl_priv_signal object diff --git a/tests/signal-test.c b/tests/signal-test.c index 7bbaa9fc..f7e1bd6f 100644 --- a/tests/signal-test.c +++ b/tests/signal-test.c @@ -115,3 +115,44 @@ TEST(signal_emit_to_more_listeners) assert(3 * counter == count); } + +struct signal_emit_mutable_data { + int count; + struct wl_listener *remove_listener; +}; + +static void +signal_notify_mutable(struct wl_listener *listener, void *data) +{ + struct signal_emit_mutable_data *test_data = data; + test_data->count++; +} + +static void +signal_notify_and_remove_mutable(struct wl_listener *listener, void *data) +{ + struct signal_emit_mutable_data *test_data = data; + signal_notify_mutable(listener, test_data); + wl_list_remove(&test_data->remove_listener->link); +} + +TEST(signal_emit_mutable) +{ + struct signal_emit_mutable_data data = {0}; + + /* l2 will remove l3 before l3 is notified */ + struct wl_signal signal; + struct wl_listener l1 = {.notify = signal_notify_mutable}; + struct wl_listener l2 = {.notify = signal_notify_and_remove_mutable}; + struct wl_listener l3 = {.notify = signal_notify_mutable}; + + wl_signal_init(&signal); + wl_signal_add(&signal, &l1); + wl_signal_add(&signal, &l2); + wl_signal_add(&signal, &l3); + + data.remove_listener = &l3; + wl_signal_emit_mutable(&signal, &data); + + assert(data.count == 2); +} From de57106c94c31bd3e77a53c92af4654358c2bd19 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sat, 2 Apr 2022 16:32:46 +0300 Subject: [PATCH 0815/1152] meson: Use proper type for bools Fix invalid usage of bools which violates official meson specification and thus breaks muon, an implementation of meson written in C. Signed-off-by: illiliti --- meson_options.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 4433fa0f..b8e2ec60 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,23 +1,23 @@ option('libraries', description: 'Compile Wayland libraries', type: 'boolean', - value: 'true') + value: true) option('scanner', description: 'Compile wayland-scanner binary', type: 'boolean', - value: 'true') + value: true) option('tests', description: 'Compile Wayland tests', type: 'boolean', - value: 'true') + value: true) option('documentation', description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)', type: 'boolean', - value: 'true') + value: true) option('dtd_validation', description: 'Validate the protocol DTD (requires libxml2)', type: 'boolean', - value: 'true') + value: true) option('icon_directory', description: 'Location used to look for cursors (defaults to ${datadir}/icons if unset)', type: 'string', From d066c4bd4efce5d6b63934e839cff205fffe7af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigrid=20Solveig=20Hafl=C3=ADnud=C3=B3ttir?= Date: Tue, 29 Mar 2022 17:59:15 +0200 Subject: [PATCH 0816/1152] connection: fix asan report on sendmsg call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialiaze the entire msghdr struct to 0 before use. Example of the report fixed with this change: AddressSanitizer:DEADLYSIGNAL ================================================================= ==20035==ERROR: AddressSanitizer: SEGV on unknown address 0x2dad4dbffffa0d (pc 0x0055555c7488 bp 0x007fffffc760 sp 0x007fffffc760 T0) ==20035==The signal is caused by a READ memory access. #0 0x55555c7488 in read_msghdr(void*, __sanitizer::__sanitizer_msghdr*, long) (/home/ftrvx/w/_/uxn/bin/uxnemu+0x77488) #1 0x55555c810c in sendmsg (/home/ftrvx/w/_/uxn/bin/uxnemu+0x7810c) #2 0x7ff7f2db20 in wl_connection_flush /home/ftrvx/q/wayland/build/../src/connection.c:315:10 #3 0x7ff7f2d014 in wl_display_flush /home/ftrvx/q/wayland/build/../src/wayland-client.c:2154:9 #4 0x7ff7e80bc0 (/lib/libSDL2-2.0.so.0+0x104bc0) #5 0x7ff7e523b0 (/lib/libSDL2-2.0.so.0+0xd63b0) #6 0x7ff7e534e4 (/lib/libSDL2-2.0.so.0+0xd74e4) #7 0x7ff7e535e8 (/lib/libSDL2-2.0.so.0+0xd75e8) #8 0x7ff7daad54 (/lib/libSDL2-2.0.so.0+0x2ed54) #9 0x7ff7dab130 (/lib/libSDL2-2.0.so.0+0x2f130) #10 0x555565bb40 in main /home/ftrvx/w/_/uxn/src/uxnemu.c:519:2 #11 0x7ff7f62484 in libc_start_main_stage2 /builddir/musl-1.1.24/src/env/__libc_start_main.c:94:2 AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (/home/ftrvx/w/_/uxn/bin/uxnemu+0x77488) in read_msghdr(void*, __sanitizer::__sanitizer_msghdr*, long) ==20035==ABORTING Signed-off-by: Sigrid Solveig Haflínudóttir --- src/connection.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/connection.c b/src/connection.c index 3a4ab478..20e2c473 100644 --- a/src/connection.c +++ b/src/connection.c @@ -289,7 +289,7 @@ int wl_connection_flush(struct wl_connection *connection) { struct iovec iov[2]; - struct msghdr msg; + struct msghdr msg = {0}; char cmsg[CLEN]; int len = 0, count, clen; uint32_t tail; @@ -303,13 +303,10 @@ wl_connection_flush(struct wl_connection *connection) build_cmsg(&connection->fds_out, cmsg, &clen); - msg.msg_name = NULL; - msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; msg.msg_control = (clen > 0) ? cmsg : NULL; msg.msg_controllen = clen; - msg.msg_flags = 0; do { len = sendmsg(connection->fd, &msg, From 2bcc27ff368bb04a86d1cae3d8e62fc31c4bfa54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigrid=20Solveig=20Hafl=C3=ADnud=C3=B3ttir?= Date: Tue, 29 Mar 2022 18:51:15 +0200 Subject: [PATCH 0817/1152] connection: change clen type in build_cmsg to size_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid implicit conversion since msg_control's type is size_t. Signed-off-by: Sigrid Solveig Haflínudóttir --- src/connection.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index 20e2c473..bf976762 100644 --- a/src/connection.c +++ b/src/connection.c @@ -231,7 +231,7 @@ wl_connection_consume(struct wl_connection *connection, size_t size) } static void -build_cmsg(struct wl_ring_buffer *buffer, char *data, int *clen) +build_cmsg(struct wl_ring_buffer *buffer, char *data, size_t *clen) { struct cmsghdr *cmsg; size_t size; @@ -291,7 +291,8 @@ wl_connection_flush(struct wl_connection *connection) struct iovec iov[2]; struct msghdr msg = {0}; char cmsg[CLEN]; - int len = 0, count, clen; + int len = 0, count; + size_t clen; uint32_t tail; if (!connection->want_flush) From 6c424e9d4c92087958928492e2b5635d4d5f2b36 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Mon, 10 Jan 2022 15:10:07 +0100 Subject: [PATCH 0818/1152] shm: Close file descriptors not needed Commit 5a981ee8 implemented a fallback path for platforms which do not support mremap() such as FreeBSD. To do so, the file descriptor for the mmap() is not closed immediately but instead kept as long as the pool exists. That induces more file descriptors kept open for longer, which in turn may cause problems as wl_shm may be using a lot of file descriptors, especially with Xwayland which can create a lot of pixmaps on behalf of its X11 clients. For platforms where mremap() is available, keeping those file descriptors opened is a bit of a waste and may cause exhaustion of file descriptors sooner that before commit 5a981ee8. Only keep the mmap() file descriptor open on platforms which do not implement mremap() and close it immediately as before on others. Signed-off-by: Olivier Fourdan Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1283 --- src/wayland-shm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 28c550dd..c4cd390c 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -65,10 +65,12 @@ struct wl_shm_pool { char *data; ssize_t size; ssize_t new_size; +#ifndef MREMAP_MAYMOVE /* The following three fields are needed for mremap() emulation. */ int mmap_fd; int mmap_flags; int mmap_prot; +#endif bool sigbus_is_impossible; }; @@ -153,7 +155,9 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external) return; munmap(pool->data, pool->size); +#ifndef MREMAP_MAYMOVE close(pool->mmap_fd); +#endif free(pool); } @@ -344,10 +348,14 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, strerror(errno)); goto err_free; } +#ifndef MREMAP_MAYMOVE /* We may need to keep the fd, prot and flags to emulate mremap(). */ pool->mmap_fd = fd; pool->mmap_prot = prot; pool->mmap_flags = flags; +#else + close(fd); +#endif pool->resource = wl_resource_create(client, &wl_shm_pool_interface, 1, id); if (!pool->resource) { From ff972f85b245d6564ec30c739a73437bcf7fac0e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 29 Mar 2022 10:16:17 +0200 Subject: [PATCH 0819/1152] os: drop unnecessary memcpy in wl_os_mremap_maymove FreeBSD doesn't support mremap [1], so we have a fallback implementation based on munmap+mmap. We memcpy from the old memory region to the new one, however this is unnecessary because the new mapping references the same file as the old one. Use msync to make sure any pending write is flushed to the underlying file before we map the new region. [1]: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=59912 Signed-off-by: Simon Ser --- src/wayland-os.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/wayland-os.c b/src/wayland-os.c index 27c6035a..a9066cae 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -231,21 +231,22 @@ wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size, ssize_t new_size, int prot, int flags) { void *result; - /* - * We could try mapping a new block immediately after the current one + + /* Make sure any pending write is flushed. */ + if (msync(old_data, *old_size, MS_SYNC) != 0) + return MAP_FAILED; + + /* We could try mapping a new block immediately after the current one * with MAP_FIXED, however that is not guaranteed to work and breaks * on CHERI-enabled architectures since the data pointer will still - * have the bounds of the previous allocation. As this is not a - * performance-critical path, we always map a new region and copy the - * old data to the new region. + * have the bounds of the previous allocation. */ result = mmap(NULL, new_size, prot, flags, fd, 0); - if (result != MAP_FAILED) { - /* Copy the data over and unmap the old mapping. */ - memcpy(result, old_data, *old_size); - if (munmap(old_data, *old_size) == 0) { - *old_size = 0; /* successfully unmapped old data. */ - } - } + if (result == MAP_FAILED) + return MAP_FAILED; + + if (munmap(old_data, *old_size) == 0) + *old_size = 0; + return result; } From 1078ee4993cc45a77bf7af79cb3f307a132123c6 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Tue, 5 Oct 2021 10:06:07 -0400 Subject: [PATCH 0820/1152] wl_shell is not mandatory Even though it is part of wayland.xml, wl_shell is not mandatory for compositors to implement, and may be removed in a future version. Signed-off-by: Demi Marie Obenour --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 4389262a..1da3db9d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1057,7 +1057,8 @@ a basic surface. Note! This protocol is deprecated and not intended for production use. - For desktop-style user interfaces, use xdg_shell. + For desktop-style user interfaces, use xdg_shell. Compositors and clients + should not implement this interface. From 04efea1727f243ac1d243cee40daad1692fe2f90 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 May 2022 11:24:11 +0200 Subject: [PATCH 0821/1152] Remove publish-doc We don't use this script anymore. Signed-off-by: Simon Ser --- publish-doc | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100755 publish-doc diff --git a/publish-doc b/publish-doc deleted file mode 100755 index 80fc22a0..00000000 --- a/publish-doc +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -e - -[ -e doc ] || (echo "Run this from the project root" && exit 1) - -make - -DOC_HTML=./doc/publican/Wayland/en-US/html/ - -[ -e "${DOC_HTML}" ] || (echo "HTML documentation failed to build at ${DOC_HTML}" && exit 1) - -chmod -R g+x ${DOC_HTML} - -rsync --delete -avz ${DOC_HTML} freedesktop.org:/srv/wayland.freedesktop.org/www/docs/html/ From 2dcc35af81cfc894335088a3843fc26af7ac9306 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 May 2022 21:57:24 +0200 Subject: [PATCH 0822/1152] cursor: use MAP_FAILED instead of hardcoded constant Signed-off-by: Simon Ser --- cursor/wayland-cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index b3495e0c..3501088a 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -92,7 +92,7 @@ shm_pool_resize(struct shm_pool *pool, int size) pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, pool->fd, 0); - if (pool->data == (void *)-1) + if (pool->data == MAP_FAILED) return 0; pool->size = size; From 9402afc353bb359b4d87622451abd635d111d356 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 May 2022 11:14:00 +0200 Subject: [PATCH 0823/1152] build: sanity check options Fail when tests/documentation is enabled without libraries. Fail when neither scanner nor libraries is enabled, because we don't build anything in that case. Signed-off-by: Simon Ser --- doc/meson.build | 4 ++++ meson.build | 12 ++++++------ src/meson.build | 4 ++++ tests/meson.build | 4 ++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/doc/meson.build b/doc/meson.build index 57c71802..44fda2ab 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -1,3 +1,7 @@ +if not get_option('libraries') + error('-Ddocumentation=true requires -Dlibraries=true') +endif + dot = find_program('dot') doxygen = find_program('doxygen') xsltproc = find_program('xsltproc') diff --git a/meson.build b/meson.build index e7fc3eef..8e951b9f 100644 --- a/meson.build +++ b/meson.build @@ -118,12 +118,12 @@ subdir('src') if get_option('libraries') subdir('cursor') subdir('egl') - if get_option('tests') - subdir('tests') - endif - if get_option('documentation') - subdir('doc') - endif +endif +if get_option('tests') + subdir('tests') +endif +if get_option('documentation') + subdir('doc') endif if get_option('scanner') diff --git a/src/meson.build b/src/meson.build index 266c8b1e..a601724b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,3 +1,7 @@ +if not (get_option('scanner') or get_option('libraries')) + error('Either -Dscanner=true or -Dlibraries=true is required') +endif + wayland_version_h = configuration_data() wayland_version_h.set('WAYLAND_VERSION', meson.project_version()) wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int()) diff --git a/tests/meson.build b/tests/meson.build index ffb5136c..5efd6f7a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,3 +1,7 @@ +if not get_option('libraries') + error('-Dtests=true requires -Dlibraries=true') +endif + test_runner = static_library( 'test-runner', sources: [ From f7ca2c65f3bffd45b54d32d4ccf467c31d48a39b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 May 2022 17:21:11 +0200 Subject: [PATCH 0824/1152] docs/publican: ensure output encoding is UTF-8 Without this, DocBook picks the output encoding and on some setups we end up with ISO-8859-1. Tested by booting a fresh Alpine VM, verifying that the generated HTML is using the incorrect charset, applying the patch, and verifying that the generated HTML is fixed. Signed-off-by: Simon Ser --- doc/publican/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 60305f49..eac3e9b2 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -7,6 +7,7 @@ custom_target( command: [ xmlto, '--skip-validation', + '--stringparam', 'chunker.output.encoding=UTF-8', '--stringparam', 'chunk.section.depth=0', '--stringparam', 'toc.section.depth=1', '--stringparam', 'generate.consistent.ids=1', From b19488c7154b902354cb26a27f11415d7799b0b2 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 28 Jan 2022 13:18:37 -0600 Subject: [PATCH 0825/1152] util: Limit size of wl_map Since server IDs are basically indistinguishable from really big client IDs at many points in the source, it's theoretically possible to overflow a map and either overflow server IDs into the client ID space, or grow client IDs into the server ID space. This would currently take a massive amount of RAM, but the definition of massive changes yearly. Prevent this by placing a ridiculous but arbitrary upper bound on the number of items we can put in a map: 0xF00000, somewhere over 15 million. This should satisfy pathological clients without restriction, but stays well clear of the 0xFF000000 transition point between server and client IDs. It will still take an improbable amount of RAM to hit this, and a client could still exhaust all RAM in this way, but our goal is to prevent overflow and undefined behaviour. Fixes #224 Signed-off-by: Derek Foreman --- src/wayland-private.h | 1 + src/wayland-util.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/wayland-private.h b/src/wayland-private.h index 210451e4..9274f1b8 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -45,6 +45,7 @@ #define WL_MAP_SERVER_SIDE 0 #define WL_MAP_CLIENT_SIDE 1 #define WL_SERVER_ID_START 0xff000000 +#define WL_MAP_MAX_OBJECTS 0x00f00000 #define WL_CLOSURE_MAX_ARGS 20 struct wl_object { diff --git a/src/wayland-util.c b/src/wayland-util.c index e82b7d26..41f0986b 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -198,6 +198,7 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) union map_entry *start, *entry; struct wl_array *entries; uint32_t base; + uint32_t count; if (map->side == WL_MAP_CLIENT_SIDE) { entries = &map->client_entries; @@ -218,10 +219,25 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) start = entries->data; } + /* wl_array only grows, so if we have too many objects at + * this point there's no way to clean up. We could be more + * pro-active about trying to avoid this allocation, but + * it doesn't really matter because at this point there is + * nothing to be done but disconnect the client and delete + * the whole array either way. + */ + count = entry - start; + if (count > WL_MAP_MAX_OBJECTS) { + /* entry->data is freshly malloced garbage, so we'd + * better make it a NULL so wl_map_for_each doesn't + * dereference it later. */ + entry->data = NULL; + return 0; + } entry->data = data; entry->next |= (flags & 0x1) << 1; - return (entry - start) + base; + return count + base; } int @@ -238,6 +254,9 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) i -= WL_SERVER_ID_START; } + if (i > WL_MAP_MAX_OBJECTS) + return -1; + count = entries->size / sizeof *start; if (count < i) { errno = EINVAL; @@ -280,8 +299,10 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) i -= WL_SERVER_ID_START; } - count = entries->size / sizeof *start; + if (i > WL_MAP_MAX_OBJECTS) + return -1; + count = entries->size / sizeof *start; if (count < i) { errno = EINVAL; return -1; From d01868413ff12b09729a07b0f1ccef2adb40361a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 12 May 2022 19:01:26 +0200 Subject: [PATCH 0826/1152] server: add wl_global_get_version Add a helper to check the advertised version of a global. This can be handy when checking whether a compositor feature is supported, instead of having to store the version passed to wl_global_create separately. Signed-off-by: Simon Ser --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index ab5b4487..7a1375f8 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -279,6 +279,9 @@ wl_display_set_global_filter(struct wl_display *display, const struct wl_interface * wl_global_get_interface(const struct wl_global *global); +uint32_t +wl_global_get_version(const struct wl_global *global); + struct wl_display * wl_global_get_display(const struct wl_global *global); diff --git a/src/wayland-server.c b/src/wayland-server.c index 71b03606..93e42c7a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1315,6 +1315,20 @@ wl_global_get_interface(const struct wl_global *global) return global->interface; } +/** Get the version of the given global. + * + * \param global The global object. + * \return The version advertised by the global. + * + * \memberof wl_global + * \since 1.21 + */ +WL_EXPORT uint32_t +wl_global_get_version(const struct wl_global *global) +{ + return global->version; +} + /** Get the display object for the given global * * \param global The global object From 4ea5ad1d11973344446d4078cfd45114101442b0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 16:57:15 +0200 Subject: [PATCH 0827/1152] cursor: remove private Xcursor int typedefs Just use the types directly instead. Signed-off-by: Simon Ser --- cursor/xcursor.c | 69 ++++++++++++++++++++++++------------------------ cursor/xcursor.h | 22 ++++++--------- 2 files changed, 43 insertions(+), 48 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 744bbcd9..73a9f332 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -25,6 +25,7 @@ #define _GNU_SOURCE #include "xcursor.h" +#include #include #include #include @@ -93,16 +94,16 @@ #define XCURSOR_FILE_TOC_LEN (3 * 4) typedef struct _XcursorFileToc { - XcursorUInt type; /* chunk type */ - XcursorUInt subtype; /* subtype (size for images) */ - XcursorUInt position; /* absolute position in file */ + uint32_t type; /* chunk type */ + uint32_t subtype; /* subtype (size for images) */ + uint32_t position; /* absolute position in file */ } XcursorFileToc; typedef struct _XcursorFileHeader { - XcursorUInt magic; /* magic number */ - XcursorUInt header; /* byte length of header */ - XcursorUInt version; /* file version number */ - XcursorUInt ntoc; /* number of toc entries */ + uint32_t magic; /* magic number */ + uint32_t header; /* byte length of header */ + uint32_t version; /* file version number */ + uint32_t ntoc; /* number of toc entries */ XcursorFileToc *tocs; /* table of contents */ } XcursorFileHeader; @@ -125,10 +126,10 @@ typedef struct _XcursorFileHeader { #define XCURSOR_CHUNK_HEADER_LEN (4 * 4) typedef struct _XcursorChunkHeader { - XcursorUInt header; /* bytes in chunk header */ - XcursorUInt type; /* chunk type */ - XcursorUInt subtype; /* chunk subtype (size for images) */ - XcursorUInt version; /* version of this type */ + uint32_t header; /* bytes in chunk header */ + uint32_t type; /* chunk type */ + uint32_t subtype; /* chunk subtype (size for images) */ + uint32_t version; /* version of this type */ } XcursorChunkHeader; /* @@ -154,8 +155,8 @@ typedef struct _XcursorChunkHeader { #define XCURSOR_COMMENT_MAX_LEN 0x100000 typedef struct _XcursorComment { - XcursorUInt version; - XcursorUInt comment_type; + uint32_t version; + uint32_t comment_type; char *comment; } XcursorComment; @@ -209,11 +210,11 @@ XcursorImageCreate (int width, int height) return NULL; image = malloc (sizeof (XcursorImage) + - width * height * sizeof (XcursorPixel)); + width * height * sizeof (uint32_t)); if (!image) return NULL; image->version = XCURSOR_IMAGE_VERSION; - image->pixels = (XcursorPixel *) (image + 1); + image->pixels = (uint32_t *) (image + 1); image->size = width > height ? width : height; image->width = width; image->height = height; @@ -276,8 +277,8 @@ XcursorImagesSetName (XcursorImages *images, const char *name) images->name = new; } -static XcursorBool -_XcursorReadUInt (XcursorFile *file, XcursorUInt *u) +static bool +_XcursorReadUInt (XcursorFile *file, uint32_t *u) { unsigned char bytes[4]; @@ -287,10 +288,10 @@ _XcursorReadUInt (XcursorFile *file, XcursorUInt *u) if ((*file->read) (file, bytes, 4) != 4) return XcursorFalse; - *u = ((XcursorUInt)(bytes[0]) << 0) | - ((XcursorUInt)(bytes[1]) << 8) | - ((XcursorUInt)(bytes[2]) << 16) | - ((XcursorUInt)(bytes[3]) << 24); + *u = ((uint32_t)(bytes[0]) << 0) | + ((uint32_t)(bytes[1]) << 8) | + ((uint32_t)(bytes[2]) << 16) | + ((uint32_t)(bytes[3]) << 24); return XcursorTrue; } @@ -301,7 +302,7 @@ _XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) } static XcursorFileHeader * -_XcursorFileHeaderCreate (XcursorUInt ntoc) +_XcursorFileHeaderCreate (uint32_t ntoc) { XcursorFileHeader *fileHeader; @@ -323,7 +324,7 @@ static XcursorFileHeader * _XcursorReadFileHeader (XcursorFile *file) { XcursorFileHeader head, *fileHeader; - XcursorUInt skip; + uint32_t skip; unsigned int n; if (!file) @@ -367,7 +368,7 @@ _XcursorReadFileHeader (XcursorFile *file) return fileHeader; } -static XcursorBool +static bool _XcursorSeekToToc (XcursorFile *file, XcursorFileHeader *fileHeader, int toc) @@ -378,7 +379,7 @@ _XcursorSeekToToc (XcursorFile *file, return XcursorTrue; } -static XcursorBool +static bool _XcursorFileReadChunkHeader (XcursorFile *file, XcursorFileHeader *fileHeader, int toc, @@ -405,15 +406,15 @@ _XcursorFileReadChunkHeader (XcursorFile *file, #define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) -static XcursorDim +static uint32_t _XcursorFindBestSize (XcursorFileHeader *fileHeader, - XcursorDim size, + uint32_t size, int *nsizesp) { unsigned int n; int nsizes = 0; - XcursorDim bestSize = 0; - XcursorDim thisSize; + uint32_t bestSize = 0; + uint32_t thisSize; if (!fileHeader || !nsizesp) return 0; @@ -437,11 +438,11 @@ _XcursorFindBestSize (XcursorFileHeader *fileHeader, static int _XcursorFindImageToc (XcursorFileHeader *fileHeader, - XcursorDim size, + uint32_t size, int count) { unsigned int toc; - XcursorDim thisSize; + uint32_t thisSize; if (!fileHeader) return 0; @@ -471,7 +472,7 @@ _XcursorReadImage (XcursorFile *file, XcursorImage head; XcursorImage *image; int n; - XcursorPixel *p; + uint32_t *p; if (!file || !fileHeader) return NULL; @@ -525,7 +526,7 @@ static XcursorImages * XcursorXcFileLoadImages (XcursorFile *file, int size) { XcursorFileHeader *fileHeader; - XcursorDim bestSize; + uint32_t bestSize; int nsize; XcursorImages *images; int n; @@ -536,7 +537,7 @@ XcursorXcFileLoadImages (XcursorFile *file, int size) fileHeader = _XcursorReadFileHeader (file); if (!fileHeader) return NULL; - bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize); + bestSize = _XcursorFindBestSize (fileHeader, (uint32_t) size, &nsize); if (!bestSize) { _XcursorFileHeaderDestroy (fileHeader); diff --git a/cursor/xcursor.h b/cursor/xcursor.h index fe2339a4..e200280c 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -28,21 +28,15 @@ #include -typedef int XcursorBool; -typedef uint32_t XcursorUInt; - -typedef XcursorUInt XcursorDim; -typedef XcursorUInt XcursorPixel; - typedef struct _XcursorImage { - XcursorUInt version; /* version of the image data */ - XcursorDim size; /* nominal size for matching */ - XcursorDim width; /* actual width */ - XcursorDim height; /* actual height */ - XcursorDim xhot; /* hot spot x (must be inside image) */ - XcursorDim yhot; /* hot spot y (must be inside image) */ - XcursorUInt delay; /* animation delay to next frame (ms) */ - XcursorPixel *pixels; /* pointer to pixels */ + uint32_t version; /* version of the image data */ + uint32_t size; /* nominal size for matching */ + uint32_t width; /* actual width */ + uint32_t height; /* actual height */ + uint32_t xhot; /* hot spot x (must be inside image) */ + uint32_t yhot; /* hot spot y (must be inside image) */ + uint32_t delay; /* animation delay to next frame (ms) */ + uint32_t *pixels; /* pointer to pixels */ } XcursorImage; /* From 7658cff241d7d89fba3733e0f3d0718993308450 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:01:18 +0200 Subject: [PATCH 0828/1152] cursor: drop XcursorTrue and XcursorFalse Just use instead. Signed-off-by: Simon Ser --- cursor/xcursor.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 73a9f332..60d2b99f 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -31,13 +31,6 @@ #include #include -/* - * From libXcursor/include/X11/extensions/Xcursor.h - */ - -#define XcursorTrue 1 -#define XcursorFalse 0 - /* * Cursor files start with a header. The header * contains a magic number, a version number and a @@ -283,16 +276,16 @@ _XcursorReadUInt (XcursorFile *file, uint32_t *u) unsigned char bytes[4]; if (!file || !u) - return XcursorFalse; + return false; if ((*file->read) (file, bytes, 4) != 4) - return XcursorFalse; + return false; *u = ((uint32_t)(bytes[0]) << 0) | ((uint32_t)(bytes[1]) << 8) | ((uint32_t)(bytes[2]) << 16) | ((uint32_t)(bytes[3]) << 24); - return XcursorTrue; + return true; } static void @@ -375,8 +368,8 @@ _XcursorSeekToToc (XcursorFile *file, { if (!file || !fileHeader || \ (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) - return XcursorFalse; - return XcursorTrue; + return false; + return true; } static bool @@ -386,22 +379,22 @@ _XcursorFileReadChunkHeader (XcursorFile *file, XcursorChunkHeader *chunkHeader) { if (!file || !fileHeader || !chunkHeader) - return XcursorFalse; + return false; if (!_XcursorSeekToToc (file, fileHeader, toc)) - return XcursorFalse; + return false; if (!_XcursorReadUInt (file, &chunkHeader->header)) - return XcursorFalse; + return false; if (!_XcursorReadUInt (file, &chunkHeader->type)) - return XcursorFalse; + return false; if (!_XcursorReadUInt (file, &chunkHeader->subtype)) - return XcursorFalse; + return false; if (!_XcursorReadUInt (file, &chunkHeader->version)) - return XcursorFalse; + return false; /* sanity check */ if (chunkHeader->type != fileHeader->tocs[toc].type || chunkHeader->subtype != fileHeader->tocs[toc].subtype) - return XcursorFalse; - return XcursorTrue; + return false; + return true; } #define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) From 13d4ae01cbc70f0fcd37d883869382f3a567425a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:02:49 +0200 Subject: [PATCH 0829/1152] cursor: drop XCURSOR_LIB_* defines These are unused. Signed-off-by: Simon Ser --- cursor/xcursor.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 60d2b99f..87fe83c4 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -64,18 +64,6 @@ #define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ -/* - * Current Xcursor version number. Will be substituted by configure - * from the version in the libXcursor configure.ac file. - */ - -#define XCURSOR_LIB_MAJOR 1 -#define XCURSOR_LIB_MINOR 1 -#define XCURSOR_LIB_REVISION 13 -#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \ - (XCURSOR_LIB_MINOR * 100) + \ - (XCURSOR_LIB_REVISION)) - /* * This version number is stored in cursor files; changes to the * file format require updating this version number From 5f5f1da691f9888c94552ab72a2cca61c01a12ba Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:10:53 +0200 Subject: [PATCH 0830/1152] cursor: drop whitespace before parens in function calls This is in line with the rest of the Wayland code style. Signed-off-by: Simon Ser --- cursor/xcursor.c | 248 +++++++++++++++++++++++------------------------ cursor/xcursor.h | 6 +- 2 files changed, 127 insertions(+), 127 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 87fe83c4..c497af84 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -181,7 +181,7 @@ typedef struct _XcursorComments { */ static XcursorImage * -XcursorImageCreate (int width, int height) +XcursorImageCreate(int width, int height) { XcursorImage *image; @@ -190,8 +190,8 @@ XcursorImageCreate (int width, int height) if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) return NULL; - image = malloc (sizeof (XcursorImage) + - width * height * sizeof (uint32_t)); + image = malloc(sizeof(XcursorImage) + + width * height * sizeof(uint32_t)); if (!image) return NULL; image->version = XCURSOR_IMAGE_VERSION; @@ -204,18 +204,18 @@ XcursorImageCreate (int width, int height) } static void -XcursorImageDestroy (XcursorImage *image) +XcursorImageDestroy(XcursorImage *image) { - free (image); + free(image); } static XcursorImages * -XcursorImagesCreate (int size) +XcursorImagesCreate(int size) { XcursorImages *images; - images = malloc (sizeof (XcursorImages) + - size * sizeof (XcursorImage *)); + images = malloc(sizeof(XcursorImages) + + size * sizeof(XcursorImage *)); if (!images) return NULL; images->nimage = 0; @@ -225,7 +225,7 @@ XcursorImagesCreate (int size) } void -XcursorImagesDestroy (XcursorImages *images) +XcursorImagesDestroy(XcursorImages *images) { int n; @@ -233,40 +233,40 @@ XcursorImagesDestroy (XcursorImages *images) return; for (n = 0; n < images->nimage; n++) - XcursorImageDestroy (images->images[n]); + XcursorImageDestroy(images->images[n]); if (images->name) - free (images->name); - free (images); + free(images->name); + free(images); } static void -XcursorImagesSetName (XcursorImages *images, const char *name) +XcursorImagesSetName(XcursorImages *images, const char *name) { char *new; if (!images || !name) return; - new = malloc (strlen (name) + 1); + new = malloc(strlen(name) + 1); if (!new) return; - strcpy (new, name); + strcpy(new, name); if (images->name) - free (images->name); + free(images->name); images->name = new; } static bool -_XcursorReadUInt (XcursorFile *file, uint32_t *u) +_XcursorReadUInt(XcursorFile *file, uint32_t *u) { unsigned char bytes[4]; if (!file || !u) return false; - if ((*file->read) (file, bytes, 4) != 4) + if ((*file->read)(file, bytes, 4) != 4) return false; *u = ((uint32_t)(bytes[0]) << 0) | @@ -277,20 +277,20 @@ _XcursorReadUInt (XcursorFile *file, uint32_t *u) } static void -_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) +_XcursorFileHeaderDestroy(XcursorFileHeader *fileHeader) { - free (fileHeader); + free(fileHeader); } static XcursorFileHeader * -_XcursorFileHeaderCreate (uint32_t ntoc) +_XcursorFileHeaderCreate(uint32_t ntoc) { XcursorFileHeader *fileHeader; if (ntoc > 0x10000) return NULL; - fileHeader = malloc (sizeof (XcursorFileHeader) + - ntoc * sizeof (XcursorFileToc)); + fileHeader = malloc(sizeof(XcursorFileHeader) + + ntoc * sizeof(XcursorFileToc)); if (!fileHeader) return NULL; fileHeader->magic = XCURSOR_MAGIC; @@ -302,7 +302,7 @@ _XcursorFileHeaderCreate (uint32_t ntoc) } static XcursorFileHeader * -_XcursorReadFileHeader (XcursorFile *file) +_XcursorReadFileHeader(XcursorFile *file) { XcursorFileHeader head, *fileHeader; uint32_t skip; @@ -311,21 +311,21 @@ _XcursorReadFileHeader (XcursorFile *file) if (!file) return NULL; - if (!_XcursorReadUInt (file, &head.magic)) + if (!_XcursorReadUInt(file, &head.magic)) return NULL; if (head.magic != XCURSOR_MAGIC) return NULL; - if (!_XcursorReadUInt (file, &head.header)) + if (!_XcursorReadUInt(file, &head.header)) return NULL; - if (!_XcursorReadUInt (file, &head.version)) + if (!_XcursorReadUInt(file, &head.version)) return NULL; - if (!_XcursorReadUInt (file, &head.ntoc)) + if (!_XcursorReadUInt(file, &head.ntoc)) return NULL; skip = head.header - XCURSOR_FILE_HEADER_LEN; if (skip) - if ((*file->seek) (file, skip, SEEK_CUR) == EOF) + if ((*file->seek)(file, skip, SEEK_CUR) == EOF) return NULL; - fileHeader = _XcursorFileHeaderCreate (head.ntoc); + fileHeader = _XcursorFileHeaderCreate(head.ntoc); if (!fileHeader) return NULL; fileHeader->magic = head.magic; @@ -334,49 +334,49 @@ _XcursorReadFileHeader (XcursorFile *file) fileHeader->ntoc = head.ntoc; for (n = 0; n < fileHeader->ntoc; n++) { - if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type)) + if (!_XcursorReadUInt(file, &fileHeader->tocs[n].type)) break; - if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype)) + if (!_XcursorReadUInt(file, &fileHeader->tocs[n].subtype)) break; - if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position)) + if (!_XcursorReadUInt(file, &fileHeader->tocs[n].position)) break; } if (n != fileHeader->ntoc) { - _XcursorFileHeaderDestroy (fileHeader); + _XcursorFileHeaderDestroy(fileHeader); return NULL; } return fileHeader; } static bool -_XcursorSeekToToc (XcursorFile *file, - XcursorFileHeader *fileHeader, - int toc) +_XcursorSeekToToc(XcursorFile *file, + XcursorFileHeader *fileHeader, + int toc) { if (!file || !fileHeader || \ - (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) + (*file->seek)(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) return false; return true; } static bool -_XcursorFileReadChunkHeader (XcursorFile *file, - XcursorFileHeader *fileHeader, - int toc, - XcursorChunkHeader *chunkHeader) +_XcursorFileReadChunkHeader(XcursorFile *file, + XcursorFileHeader *fileHeader, + int toc, + XcursorChunkHeader *chunkHeader) { if (!file || !fileHeader || !chunkHeader) return false; - if (!_XcursorSeekToToc (file, fileHeader, toc)) + if (!_XcursorSeekToToc(file, fileHeader, toc)) return false; - if (!_XcursorReadUInt (file, &chunkHeader->header)) + if (!_XcursorReadUInt(file, &chunkHeader->header)) return false; - if (!_XcursorReadUInt (file, &chunkHeader->type)) + if (!_XcursorReadUInt(file, &chunkHeader->type)) return false; - if (!_XcursorReadUInt (file, &chunkHeader->subtype)) + if (!_XcursorReadUInt(file, &chunkHeader->subtype)) return false; - if (!_XcursorReadUInt (file, &chunkHeader->version)) + if (!_XcursorReadUInt(file, &chunkHeader->version)) return false; /* sanity check */ if (chunkHeader->type != fileHeader->tocs[toc].type || @@ -388,7 +388,7 @@ _XcursorFileReadChunkHeader (XcursorFile *file, #define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) static uint32_t -_XcursorFindBestSize (XcursorFileHeader *fileHeader, +_XcursorFindBestSize(XcursorFileHeader *fileHeader, uint32_t size, int *nsizesp) { @@ -405,7 +405,7 @@ _XcursorFindBestSize (XcursorFileHeader *fileHeader, if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) continue; thisSize = fileHeader->tocs[n].subtype; - if (!bestSize || dist (thisSize, size) < dist (bestSize, size)) + if (!bestSize || dist(thisSize, size) < dist(bestSize, size)) { bestSize = thisSize; nsizes = 1; @@ -418,9 +418,9 @@ _XcursorFindBestSize (XcursorFileHeader *fileHeader, } static int -_XcursorFindImageToc (XcursorFileHeader *fileHeader, - uint32_t size, - int count) +_XcursorFindImageToc(XcursorFileHeader *fileHeader, + uint32_t size, + int count) { unsigned int toc; uint32_t thisSize; @@ -445,7 +445,7 @@ _XcursorFindImageToc (XcursorFileHeader *fileHeader, } static XcursorImage * -_XcursorReadImage (XcursorFile *file, +_XcursorReadImage(XcursorFile *file, XcursorFileHeader *fileHeader, int toc) { @@ -458,17 +458,17 @@ _XcursorReadImage (XcursorFile *file, if (!file || !fileHeader) return NULL; - if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader)) + if (!_XcursorFileReadChunkHeader(file, fileHeader, toc, &chunkHeader)) return NULL; - if (!_XcursorReadUInt (file, &head.width)) + if (!_XcursorReadUInt(file, &head.width)) return NULL; - if (!_XcursorReadUInt (file, &head.height)) + if (!_XcursorReadUInt(file, &head.height)) return NULL; - if (!_XcursorReadUInt (file, &head.xhot)) + if (!_XcursorReadUInt(file, &head.xhot)) return NULL; - if (!_XcursorReadUInt (file, &head.yhot)) + if (!_XcursorReadUInt(file, &head.yhot)) return NULL; - if (!_XcursorReadUInt (file, &head.delay)) + if (!_XcursorReadUInt(file, &head.delay)) return NULL; /* sanity check data */ if (head.width > XCURSOR_IMAGE_MAX_SIZE || @@ -480,7 +480,7 @@ _XcursorReadImage (XcursorFile *file, return NULL; /* Create the image and initialize it */ - image = XcursorImageCreate (head.width, head.height); + image = XcursorImageCreate(head.width, head.height); if (image == NULL) return NULL; if (chunkHeader.version < image->version) @@ -493,9 +493,9 @@ _XcursorReadImage (XcursorFile *file, p = image->pixels; while (n--) { - if (!_XcursorReadUInt (file, p)) + if (!_XcursorReadUInt(file, p)) { - XcursorImageDestroy (image); + XcursorImageDestroy(image); return NULL; } p++; @@ -504,7 +504,7 @@ _XcursorReadImage (XcursorFile *file, } static XcursorImages * -XcursorXcFileLoadImages (XcursorFile *file, int size) +XcursorXcFileLoadImages(XcursorFile *file, int size) { XcursorFileHeader *fileHeader; uint32_t bestSize; @@ -515,64 +515,64 @@ XcursorXcFileLoadImages (XcursorFile *file, int size) if (!file || size < 0) return NULL; - fileHeader = _XcursorReadFileHeader (file); + fileHeader = _XcursorReadFileHeader(file); if (!fileHeader) return NULL; - bestSize = _XcursorFindBestSize (fileHeader, (uint32_t) size, &nsize); + bestSize = _XcursorFindBestSize(fileHeader, (uint32_t) size, &nsize); if (!bestSize) { - _XcursorFileHeaderDestroy (fileHeader); + _XcursorFileHeaderDestroy(fileHeader); return NULL; } - images = XcursorImagesCreate (nsize); + images = XcursorImagesCreate(nsize); if (!images) { - _XcursorFileHeaderDestroy (fileHeader); + _XcursorFileHeaderDestroy(fileHeader); return NULL; } for (n = 0; n < nsize; n++) { - toc = _XcursorFindImageToc (fileHeader, bestSize, n); + toc = _XcursorFindImageToc(fileHeader, bestSize, n); if (toc < 0) break; - images->images[images->nimage] = _XcursorReadImage (file, fileHeader, - toc); + images->images[images->nimage] = _XcursorReadImage(file, fileHeader, + toc); if (!images->images[images->nimage]) break; images->nimage++; } - _XcursorFileHeaderDestroy (fileHeader); + _XcursorFileHeaderDestroy(fileHeader); if (images->nimage != nsize) { - XcursorImagesDestroy (images); + XcursorImagesDestroy(images); images = NULL; } return images; } static int -_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len) +_XcursorStdioFileRead(XcursorFile *file, unsigned char *buf, int len) { FILE *f = file->closure; - return fread (buf, 1, len, f); + return fread(buf, 1, len, f); } static int -_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len) +_XcursorStdioFileWrite(XcursorFile *file, unsigned char *buf, int len) { FILE *f = file->closure; - return fwrite (buf, 1, len, f); + return fwrite(buf, 1, len, f); } static int -_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence) +_XcursorStdioFileSeek(XcursorFile *file, long offset, int whence) { FILE *f = file->closure; - return fseek (f, offset, whence); + return fseek(f, offset, whence); } static void -_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file) +_XcursorStdioFileInitialize(FILE *stdfile, XcursorFile *file) { file->closure = stdfile; file->read = _XcursorStdioFileRead; @@ -581,15 +581,15 @@ _XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file) } static XcursorImages * -XcursorFileLoadImages (FILE *file, int size) +XcursorFileLoadImages(FILE *file, int size) { XcursorFile f; if (!file) return NULL; - _XcursorStdioFileInitialize (file, &f); - return XcursorXcFileLoadImages (&f, size); + _XcursorStdioFileInitialize(file, &f); + return XcursorXcFileLoadImages(&f, size); } /* @@ -617,59 +617,59 @@ XcursorFileLoadImages (FILE *file, int size) * and must be freed by the caller. */ static char * -XcursorLibraryPath (void) +XcursorLibraryPath(void) { const char *env_var; char *path = NULL; int pathlen = 0; - env_var = getenv ("XCURSOR_PATH"); + env_var = getenv("XCURSOR_PATH"); if (env_var) { - path = strdup (env_var); + path = strdup(env_var); } else { - env_var = getenv ("XDG_DATA_HOME"); + env_var = getenv("XDG_DATA_HOME"); if (env_var) { - pathlen = strlen (env_var) + strlen (CURSORDIR ":" XCURSORPATH) + 1; - path = malloc (pathlen); - snprintf (path, pathlen, "%s%s", env_var, - CURSORDIR ":" XCURSORPATH); + pathlen = strlen(env_var) + strlen(CURSORDIR ":" XCURSORPATH) + 1; + path = malloc(pathlen); + snprintf(path, pathlen, "%s%s", env_var, + CURSORDIR ":" XCURSORPATH); } else { - path = strdup (XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); + path = strdup(XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); } } return path; } static void -_XcursorAddPathElt (char *path, const char *elt, int len) +_XcursorAddPathElt(char *path, const char *elt, int len) { - int pathlen = strlen (path); + int pathlen = strlen(path); /* append / if the path doesn't currently have one */ if (path[0] == '\0' || path[pathlen - 1] != '/') { - strcat (path, "/"); + strcat(path, "/"); pathlen++; } if (len == -1) - len = strlen (elt); + len = strlen(elt); /* strip leading slashes */ while (len && elt[0] == '/') { elt++; len--; } - strncpy (path + pathlen, elt, len); + strncpy(path + pathlen, elt, len); path[pathlen + len] = '\0'; } static char * -_XcursorBuildThemeDir (const char *dir, const char *theme) +_XcursorBuildThemeDir(const char *dir, const char *theme) { const char *colon; const char *tcolon; @@ -683,15 +683,15 @@ _XcursorBuildThemeDir (const char *dir, const char *theme) if (!dir || !theme) return NULL; - colon = strchr (dir, ':'); + colon = strchr(dir, ':'); if (!colon) - colon = dir + strlen (dir); + colon = dir + strlen(dir); dirlen = colon - dir; - tcolon = strchr (theme, ':'); + tcolon = strchr(theme, ':'); if (!tcolon) - tcolon = theme + strlen (theme); + tcolon = theme + strlen(theme); themelen = tcolon - theme; @@ -699,10 +699,10 @@ _XcursorBuildThemeDir (const char *dir, const char *theme) homelen = 0; if (*dir == '~') { - home = getenv ("HOME"); + home = getenv("HOME"); if (!home) return NULL; - homelen = strlen (home); + homelen = strlen(home); dir++; dirlen--; } @@ -713,40 +713,40 @@ _XcursorBuildThemeDir (const char *dir, const char *theme) */ len = 1 + homelen + 1 + dirlen + 1 + themelen + 1; - full = malloc (len); + full = malloc(len); if (!full) return NULL; full[0] = '\0'; if (home) - _XcursorAddPathElt (full, home, -1); - _XcursorAddPathElt (full, dir, dirlen); - _XcursorAddPathElt (full, theme, themelen); + _XcursorAddPathElt(full, home, -1); + _XcursorAddPathElt(full, dir, dirlen); + _XcursorAddPathElt(full, theme, themelen); return full; } static char * -_XcursorBuildFullname (const char *dir, const char *subdir, const char *file) +_XcursorBuildFullname(const char *dir, const char *subdir, const char *file) { char *full; if (!dir || !subdir || !file) return NULL; - full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1); + full = malloc(strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1); if (!full) return NULL; full[0] = '\0'; - _XcursorAddPathElt (full, dir, -1); - _XcursorAddPathElt (full, subdir, -1); - _XcursorAddPathElt (full, file, -1); + _XcursorAddPathElt(full, dir, -1); + _XcursorAddPathElt(full, subdir, -1); + _XcursorAddPathElt(full, file, -1); return full; } static const char * -_XcursorNextPath (const char *path) +_XcursorNextPath(const char *path) { - char *colon = strchr (path, ':'); + char *colon = strchr(path, ':'); if (!colon) return NULL; @@ -757,7 +757,7 @@ _XcursorNextPath (const char *path) #define XcursorSep(c) ((c) == ';' || (c) == ',') static char * -_XcursorThemeInherits (const char *full) +_XcursorThemeInherits(const char *full) { char line[8192]; char *result = NULL; @@ -766,12 +766,12 @@ _XcursorThemeInherits (const char *full) if (!full) return NULL; - f = fopen (full, "r"); + f = fopen(full, "r"); if (f) { - while (fgets (line, sizeof (line), f)) + while (fgets(line, sizeof(line), f)) { - if (!strncmp (line, "Inherits", 8)) + if (!strncmp(line, "Inherits", 8)) { char *l = line + 8; char *r; @@ -779,13 +779,13 @@ _XcursorThemeInherits (const char *full) if (*l != '=') continue; l++; while (*l == ' ') l++; - result = malloc (strlen (l) + 1); + result = malloc(strlen(l) + 1); if (result) { r = result; while (*l) { - while (XcursorSep(*l) || XcursorWhite (*l)) l++; + while (XcursorSep(*l) || XcursorWhite(*l)) l++; if (!*l) break; if (r != result) @@ -799,7 +799,7 @@ _XcursorThemeInherits (const char *full) break; } } - fclose (f); + fclose(f); } return result; } @@ -842,7 +842,7 @@ load_all_cursors_from_dir(const char *path, int size, load_callback(images, user_data); } - fclose (f); + fclose(f); free(full); } @@ -914,5 +914,5 @@ xcursor_load_theme(const char *theme, int size, if (inherits) free(inherits); - free (xcursor_path); + free(xcursor_path); } diff --git a/cursor/xcursor.h b/cursor/xcursor.h index e200280c..6650f5d8 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -49,10 +49,10 @@ typedef struct _XcursorImages { } XcursorImages; void -XcursorImagesDestroy (XcursorImages *images); +XcursorImagesDestroy(XcursorImages *images); void xcursor_load_theme(const char *theme, int size, - void (*load_callback)(XcursorImages *, void *), - void *user_data); + void (*load_callback)(XcursorImages *, void *), + void *user_data); #endif From 329be63d6ba4d52e08ae0bef78974bcf0c11ab31 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:19:31 +0200 Subject: [PATCH 0831/1152] cursor: fix define style Don't use tabs, don't align. Signed-off-by: Simon Ser --- cursor/xcursor.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index c497af84..ec642344 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -62,17 +62,17 @@ * CARD32 position absolute file position */ -#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ +#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ /* * This version number is stored in cursor files; changes to the * file format require updating this version number */ -#define XCURSOR_FILE_MAJOR 1 -#define XCURSOR_FILE_MINOR 0 -#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) -#define XCURSOR_FILE_HEADER_LEN (4 * 4) -#define XCURSOR_FILE_TOC_LEN (3 * 4) +#define XCURSOR_FILE_MAJOR 1 +#define XCURSOR_FILE_MINOR 0 +#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) +#define XCURSOR_FILE_HEADER_LEN (4 * 4) +#define XCURSOR_FILE_TOC_LEN (3 * 4) typedef struct _XcursorFileToc { uint32_t type; /* chunk type */ @@ -104,7 +104,7 @@ typedef struct _XcursorFileHeader { * CARD32 version chunk type version */ -#define XCURSOR_CHUNK_HEADER_LEN (4 * 4) +#define XCURSOR_CHUNK_HEADER_LEN (4 * 4) typedef struct _XcursorChunkHeader { uint32_t header; /* bytes in chunk header */ @@ -127,13 +127,13 @@ typedef struct _XcursorChunkHeader { * LISTofCARD8 text UTF-8 encoded text */ -#define XCURSOR_COMMENT_TYPE 0xfffe0001 -#define XCURSOR_COMMENT_VERSION 1 -#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4)) -#define XCURSOR_COMMENT_COPYRIGHT 1 -#define XCURSOR_COMMENT_LICENSE 2 -#define XCURSOR_COMMENT_OTHER 3 -#define XCURSOR_COMMENT_MAX_LEN 0x100000 +#define XCURSOR_COMMENT_TYPE 0xfffe0001 +#define XCURSOR_COMMENT_VERSION 1 +#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4)) +#define XCURSOR_COMMENT_COPYRIGHT 1 +#define XCURSOR_COMMENT_LICENSE 2 +#define XCURSOR_COMMENT_OTHER 3 +#define XCURSOR_COMMENT_MAX_LEN 0x100000 typedef struct _XcursorComment { uint32_t version; @@ -157,10 +157,10 @@ typedef struct _XcursorComment { * LISTofCARD32 pixels ARGB pixels */ -#define XCURSOR_IMAGE_TYPE 0xfffd0002 -#define XCURSOR_IMAGE_VERSION 1 -#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) -#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ +#define XCURSOR_IMAGE_TYPE 0xfffd0002 +#define XCURSOR_IMAGE_VERSION 1 +#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) +#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ typedef struct _XcursorFile XcursorFile; From b0a4e633512e966c00a47184d4a303091ca3dcdc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:20:33 +0200 Subject: [PATCH 0832/1152] cursor: fix struct declaration style Use tabs for indentation, don't use tabs to align field names. Signed-off-by: Simon Ser --- cursor/xcursor.c | 42 +++++++++++++++++++++--------------------- cursor/xcursor.h | 22 +++++++++++----------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index ec642344..90338668 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -75,17 +75,17 @@ #define XCURSOR_FILE_TOC_LEN (3 * 4) typedef struct _XcursorFileToc { - uint32_t type; /* chunk type */ - uint32_t subtype; /* subtype (size for images) */ - uint32_t position; /* absolute position in file */ + uint32_t type; /* chunk type */ + uint32_t subtype; /* subtype (size for images) */ + uint32_t position; /* absolute position in file */ } XcursorFileToc; typedef struct _XcursorFileHeader { - uint32_t magic; /* magic number */ - uint32_t header; /* byte length of header */ - uint32_t version; /* file version number */ - uint32_t ntoc; /* number of toc entries */ - XcursorFileToc *tocs; /* table of contents */ + uint32_t magic; /* magic number */ + uint32_t header; /* byte length of header */ + uint32_t version; /* file version number */ + uint32_t ntoc; /* number of toc entries */ + XcursorFileToc *tocs; /* table of contents */ } XcursorFileHeader; /* @@ -107,10 +107,10 @@ typedef struct _XcursorFileHeader { #define XCURSOR_CHUNK_HEADER_LEN (4 * 4) typedef struct _XcursorChunkHeader { - uint32_t header; /* bytes in chunk header */ - uint32_t type; /* chunk type */ - uint32_t subtype; /* chunk subtype (size for images) */ - uint32_t version; /* version of this type */ + uint32_t header; /* bytes in chunk header */ + uint32_t type; /* chunk type */ + uint32_t subtype; /* chunk subtype (size for images) */ + uint32_t version; /* version of this type */ } XcursorChunkHeader; /* @@ -136,9 +136,9 @@ typedef struct _XcursorChunkHeader { #define XCURSOR_COMMENT_MAX_LEN 0x100000 typedef struct _XcursorComment { - uint32_t version; - uint32_t comment_type; - char *comment; + uint32_t version; + uint32_t comment_type; + char *comment; } XcursorComment; /* @@ -165,15 +165,15 @@ typedef struct _XcursorComment { typedef struct _XcursorFile XcursorFile; struct _XcursorFile { - void *closure; - int (*read) (XcursorFile *file, unsigned char *buf, int len); - int (*write) (XcursorFile *file, unsigned char *buf, int len); - int (*seek) (XcursorFile *file, long offset, int whence); + void *closure; + int (*read)(XcursorFile *file, unsigned char *buf, int len); + int (*write)(XcursorFile *file, unsigned char *buf, int len); + int (*seek)(XcursorFile *file, long offset, int whence); }; typedef struct _XcursorComments { - int ncomment; /* number of comments */ - XcursorComment **comments; /* array of XcursorComment pointers */ + int ncomment; /* number of comments */ + XcursorComment **comments; /* array of XcursorComment pointers */ } XcursorComments; /* diff --git a/cursor/xcursor.h b/cursor/xcursor.h index 6650f5d8..e417904b 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -29,23 +29,23 @@ #include typedef struct _XcursorImage { - uint32_t version; /* version of the image data */ - uint32_t size; /* nominal size for matching */ - uint32_t width; /* actual width */ - uint32_t height; /* actual height */ - uint32_t xhot; /* hot spot x (must be inside image) */ - uint32_t yhot; /* hot spot y (must be inside image) */ - uint32_t delay; /* animation delay to next frame (ms) */ - uint32_t *pixels; /* pointer to pixels */ + uint32_t version; /* version of the image data */ + uint32_t size; /* nominal size for matching */ + uint32_t width; /* actual width */ + uint32_t height; /* actual height */ + uint32_t xhot; /* hot spot x (must be inside image) */ + uint32_t yhot; /* hot spot y (must be inside image) */ + uint32_t delay; /* animation delay to next frame (ms) */ + uint32_t *pixels; /* pointer to pixels */ } XcursorImage; /* * Other data structures exposed by the library API */ typedef struct _XcursorImages { - int nimage; /* number of images */ - XcursorImage **images; /* array of XcursorImage pointers */ - char *name; /* name used to load images */ + int nimage; /* number of images */ + XcursorImage **images; /* array of XcursorImage pointers */ + char *name; /* name used to load images */ } XcursorImages; void From 92e758834c4ba55cd3d7dc29b812f7fc963296f6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:28:44 +0200 Subject: [PATCH 0833/1152] cursor: fix variable declaration style Use a single space between type and variable name. Signed-off-by: Simon Ser --- cursor/xcursor.c | 92 ++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 90338668..db796da0 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -183,7 +183,7 @@ typedef struct _XcursorComments { static XcursorImage * XcursorImageCreate(int width, int height) { - XcursorImage *image; + XcursorImage *image; if (width < 0 || height < 0) return NULL; @@ -212,7 +212,7 @@ XcursorImageDestroy(XcursorImage *image) static XcursorImages * XcursorImagesCreate(int size) { - XcursorImages *images; + XcursorImages *images; images = malloc(sizeof(XcursorImages) + size * sizeof(XcursorImage *)); @@ -227,7 +227,7 @@ XcursorImagesCreate(int size) void XcursorImagesDestroy(XcursorImages *images) { - int n; + int n; if (!images) return; @@ -242,7 +242,7 @@ XcursorImagesDestroy(XcursorImages *images) static void XcursorImagesSetName(XcursorImages *images, const char *name) { - char *new; + char *new; if (!images || !name) return; @@ -261,7 +261,7 @@ XcursorImagesSetName(XcursorImages *images, const char *name) static bool _XcursorReadUInt(XcursorFile *file, uint32_t *u) { - unsigned char bytes[4]; + unsigned char bytes[4]; if (!file || !u) return false; @@ -285,7 +285,7 @@ _XcursorFileHeaderDestroy(XcursorFileHeader *fileHeader) static XcursorFileHeader * _XcursorFileHeaderCreate(uint32_t ntoc) { - XcursorFileHeader *fileHeader; + XcursorFileHeader *fileHeader; if (ntoc > 0x10000) return NULL; @@ -304,9 +304,9 @@ _XcursorFileHeaderCreate(uint32_t ntoc) static XcursorFileHeader * _XcursorReadFileHeader(XcursorFile *file) { - XcursorFileHeader head, *fileHeader; - uint32_t skip; - unsigned int n; + XcursorFileHeader head, *fileHeader; + uint32_t skip; + unsigned int n; if (!file) return NULL; @@ -393,9 +393,9 @@ _XcursorFindBestSize(XcursorFileHeader *fileHeader, int *nsizesp) { unsigned int n; - int nsizes = 0; - uint32_t bestSize = 0; - uint32_t thisSize; + int nsizes = 0; + uint32_t bestSize = 0; + uint32_t thisSize; if (!fileHeader || !nsizesp) return 0; @@ -422,8 +422,8 @@ _XcursorFindImageToc(XcursorFileHeader *fileHeader, uint32_t size, int count) { - unsigned int toc; - uint32_t thisSize; + unsigned int toc; + uint32_t thisSize; if (!fileHeader) return 0; @@ -449,11 +449,11 @@ _XcursorReadImage(XcursorFile *file, XcursorFileHeader *fileHeader, int toc) { - XcursorChunkHeader chunkHeader; - XcursorImage head; - XcursorImage *image; - int n; - uint32_t *p; + XcursorChunkHeader chunkHeader; + XcursorImage head; + XcursorImage *image; + int n; + uint32_t *p; if (!file || !fileHeader) return NULL; @@ -506,12 +506,12 @@ _XcursorReadImage(XcursorFile *file, static XcursorImages * XcursorXcFileLoadImages(XcursorFile *file, int size) { - XcursorFileHeader *fileHeader; - uint32_t bestSize; - int nsize; - XcursorImages *images; - int n; - int toc; + XcursorFileHeader *fileHeader; + uint32_t bestSize; + int nsize; + XcursorImages *images; + int n; + int toc; if (!file || size < 0) return NULL; @@ -553,21 +553,21 @@ XcursorXcFileLoadImages(XcursorFile *file, int size) static int _XcursorStdioFileRead(XcursorFile *file, unsigned char *buf, int len) { - FILE *f = file->closure; + FILE *f = file->closure; return fread(buf, 1, len, f); } static int _XcursorStdioFileWrite(XcursorFile *file, unsigned char *buf, int len) { - FILE *f = file->closure; + FILE *f = file->closure; return fwrite(buf, 1, len, f); } static int _XcursorStdioFileSeek(XcursorFile *file, long offset, int whence) { - FILE *f = file->closure; + FILE *f = file->closure; return fseek(f, offset, whence); } @@ -583,7 +583,7 @@ _XcursorStdioFileInitialize(FILE *stdfile, XcursorFile *file) static XcursorImages * XcursorFileLoadImages(FILE *file, int size) { - XcursorFile f; + XcursorFile f; if (!file) return NULL; @@ -619,9 +619,9 @@ XcursorFileLoadImages(FILE *file, int size) static char * XcursorLibraryPath(void) { - const char *env_var; - char *path = NULL; - int pathlen = 0; + const char *env_var; + char *path = NULL; + int pathlen = 0; env_var = getenv("XCURSOR_PATH"); if (env_var) @@ -648,7 +648,7 @@ XcursorLibraryPath(void) static void _XcursorAddPathElt(char *path, const char *elt, int len) { - int pathlen = strlen(path); + int pathlen = strlen(path); /* append / if the path doesn't currently have one */ if (path[0] == '\0' || path[pathlen - 1] != '/') @@ -671,14 +671,14 @@ _XcursorAddPathElt(char *path, const char *elt, int len) static char * _XcursorBuildThemeDir(const char *dir, const char *theme) { - const char *colon; - const char *tcolon; - char *full; - char *home; - int dirlen; - int homelen; - int themelen; - int len; + const char *colon; + const char *tcolon; + char *full; + char *home; + int dirlen; + int homelen; + int themelen; + int len; if (!dir || !theme) return NULL; @@ -728,7 +728,7 @@ _XcursorBuildThemeDir(const char *dir, const char *theme) static char * _XcursorBuildFullname(const char *dir, const char *subdir, const char *file) { - char *full; + char *full; if (!dir || !subdir || !file) return NULL; @@ -746,7 +746,7 @@ _XcursorBuildFullname(const char *dir, const char *subdir, const char *file) static const char * _XcursorNextPath(const char *path) { - char *colon = strchr(path, ':'); + char *colon = strchr(path, ':'); if (!colon) return NULL; @@ -759,9 +759,9 @@ _XcursorNextPath(const char *path) static char * _XcursorThemeInherits(const char *full) { - char line[8192]; - char *result = NULL; - FILE *f; + char line[8192]; + char *result = NULL; + FILE *f; if (!full) return NULL; From 450bb7c1452e901660311f1d971d007b3769b3fc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:30:05 +0200 Subject: [PATCH 0834/1152] cursor: remove unnecessary if before free free(NULL) is valid and is a no-op. Signed-off-by: Simon Ser --- cursor/xcursor.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index db796da0..fd2b3c86 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -234,8 +234,7 @@ XcursorImagesDestroy(XcursorImages *images) for (n = 0; n < images->nimage; n++) XcursorImageDestroy(images->images[n]); - if (images->name) - free(images->name); + free(images->name); free(images); } @@ -253,8 +252,7 @@ XcursorImagesSetName(XcursorImages *images, const char *name) return; strcpy(new, name); - if (images->name) - free(images->name); + free(images->name); images->name = new; } @@ -911,8 +909,6 @@ xcursor_load_theme(const char *theme, int size, for (i = inherits; i; i = _XcursorNextPath(i)) xcursor_load_theme(i, size, load_callback, user_data); - if (inherits) - free(inherits); - + free(inherits); free(xcursor_path); } From 315126d3bd9291d4d4c7bf316b9e5a3f694402c9 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Apr 2022 17:40:55 +0200 Subject: [PATCH 0835/1152] cursor: fix indentation Use tabs. Signed-off-by: Simon Ser --- cursor/xcursor.c | 818 +++++++++++++++++++++++------------------------ 1 file changed, 409 insertions(+), 409 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index fd2b3c86..acf58b14 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -183,168 +183,168 @@ typedef struct _XcursorComments { static XcursorImage * XcursorImageCreate(int width, int height) { - XcursorImage *image; + XcursorImage *image; - if (width < 0 || height < 0) - return NULL; - if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) - return NULL; + if (width < 0 || height < 0) + return NULL; + if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) + return NULL; - image = malloc(sizeof(XcursorImage) + - width * height * sizeof(uint32_t)); - if (!image) - return NULL; - image->version = XCURSOR_IMAGE_VERSION; - image->pixels = (uint32_t *) (image + 1); - image->size = width > height ? width : height; - image->width = width; - image->height = height; - image->delay = 0; - return image; + image = malloc(sizeof(XcursorImage) + + width * height * sizeof(uint32_t)); + if (!image) + return NULL; + image->version = XCURSOR_IMAGE_VERSION; + image->pixels = (uint32_t *) (image + 1); + image->size = width > height ? width : height; + image->width = width; + image->height = height; + image->delay = 0; + return image; } static void XcursorImageDestroy(XcursorImage *image) { - free(image); + free(image); } static XcursorImages * XcursorImagesCreate(int size) { - XcursorImages *images; + XcursorImages *images; - images = malloc(sizeof(XcursorImages) + - size * sizeof(XcursorImage *)); - if (!images) - return NULL; - images->nimage = 0; - images->images = (XcursorImage **) (images + 1); - images->name = NULL; - return images; + images = malloc(sizeof(XcursorImages) + + size * sizeof(XcursorImage *)); + if (!images) + return NULL; + images->nimage = 0; + images->images = (XcursorImage **) (images + 1); + images->name = NULL; + return images; } void XcursorImagesDestroy(XcursorImages *images) { - int n; + int n; - if (!images) - return; + if (!images) + return; - for (n = 0; n < images->nimage; n++) - XcursorImageDestroy(images->images[n]); - free(images->name); - free(images); + for (n = 0; n < images->nimage; n++) + XcursorImageDestroy(images->images[n]); + free(images->name); + free(images); } static void XcursorImagesSetName(XcursorImages *images, const char *name) { - char *new; + char *new; - if (!images || !name) - return; + if (!images || !name) + return; - new = malloc(strlen(name) + 1); + new = malloc(strlen(name) + 1); - if (!new) - return; + if (!new) + return; - strcpy(new, name); - free(images->name); - images->name = new; + strcpy(new, name); + free(images->name); + images->name = new; } static bool _XcursorReadUInt(XcursorFile *file, uint32_t *u) { - unsigned char bytes[4]; + unsigned char bytes[4]; - if (!file || !u) - return false; + if (!file || !u) + return false; - if ((*file->read)(file, bytes, 4) != 4) - return false; + if ((*file->read)(file, bytes, 4) != 4) + return false; - *u = ((uint32_t)(bytes[0]) << 0) | - ((uint32_t)(bytes[1]) << 8) | - ((uint32_t)(bytes[2]) << 16) | - ((uint32_t)(bytes[3]) << 24); - return true; + *u = ((uint32_t)(bytes[0]) << 0) | + ((uint32_t)(bytes[1]) << 8) | + ((uint32_t)(bytes[2]) << 16) | + ((uint32_t)(bytes[3]) << 24); + return true; } static void _XcursorFileHeaderDestroy(XcursorFileHeader *fileHeader) { - free(fileHeader); + free(fileHeader); } static XcursorFileHeader * _XcursorFileHeaderCreate(uint32_t ntoc) { - XcursorFileHeader *fileHeader; + XcursorFileHeader *fileHeader; - if (ntoc > 0x10000) - return NULL; - fileHeader = malloc(sizeof(XcursorFileHeader) + - ntoc * sizeof(XcursorFileToc)); - if (!fileHeader) - return NULL; - fileHeader->magic = XCURSOR_MAGIC; - fileHeader->header = XCURSOR_FILE_HEADER_LEN; - fileHeader->version = XCURSOR_FILE_VERSION; - fileHeader->ntoc = ntoc; - fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); - return fileHeader; + if (ntoc > 0x10000) + return NULL; + fileHeader = malloc(sizeof(XcursorFileHeader) + + ntoc * sizeof(XcursorFileToc)); + if (!fileHeader) + return NULL; + fileHeader->magic = XCURSOR_MAGIC; + fileHeader->header = XCURSOR_FILE_HEADER_LEN; + fileHeader->version = XCURSOR_FILE_VERSION; + fileHeader->ntoc = ntoc; + fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); + return fileHeader; } static XcursorFileHeader * _XcursorReadFileHeader(XcursorFile *file) { - XcursorFileHeader head, *fileHeader; - uint32_t skip; - unsigned int n; + XcursorFileHeader head, *fileHeader; + uint32_t skip; + unsigned int n; - if (!file) - return NULL; + if (!file) + return NULL; - if (!_XcursorReadUInt(file, &head.magic)) - return NULL; - if (head.magic != XCURSOR_MAGIC) - return NULL; - if (!_XcursorReadUInt(file, &head.header)) - return NULL; - if (!_XcursorReadUInt(file, &head.version)) - return NULL; - if (!_XcursorReadUInt(file, &head.ntoc)) - return NULL; - skip = head.header - XCURSOR_FILE_HEADER_LEN; - if (skip) - if ((*file->seek)(file, skip, SEEK_CUR) == EOF) - return NULL; - fileHeader = _XcursorFileHeaderCreate(head.ntoc); - if (!fileHeader) - return NULL; - fileHeader->magic = head.magic; - fileHeader->header = head.header; - fileHeader->version = head.version; - fileHeader->ntoc = head.ntoc; - for (n = 0; n < fileHeader->ntoc; n++) - { - if (!_XcursorReadUInt(file, &fileHeader->tocs[n].type)) - break; - if (!_XcursorReadUInt(file, &fileHeader->tocs[n].subtype)) - break; - if (!_XcursorReadUInt(file, &fileHeader->tocs[n].position)) - break; - } - if (n != fileHeader->ntoc) - { - _XcursorFileHeaderDestroy(fileHeader); - return NULL; - } - return fileHeader; + if (!_XcursorReadUInt(file, &head.magic)) + return NULL; + if (head.magic != XCURSOR_MAGIC) + return NULL; + if (!_XcursorReadUInt(file, &head.header)) + return NULL; + if (!_XcursorReadUInt(file, &head.version)) + return NULL; + if (!_XcursorReadUInt(file, &head.ntoc)) + return NULL; + skip = head.header - XCURSOR_FILE_HEADER_LEN; + if (skip) + if ((*file->seek)(file, skip, SEEK_CUR) == EOF) + return NULL; + fileHeader = _XcursorFileHeaderCreate(head.ntoc); + if (!fileHeader) + return NULL; + fileHeader->magic = head.magic; + fileHeader->header = head.header; + fileHeader->version = head.version; + fileHeader->ntoc = head.ntoc; + for (n = 0; n < fileHeader->ntoc; n++) + { + if (!_XcursorReadUInt(file, &fileHeader->tocs[n].type)) + break; + if (!_XcursorReadUInt(file, &fileHeader->tocs[n].subtype)) + break; + if (!_XcursorReadUInt(file, &fileHeader->tocs[n].position)) + break; + } + if (n != fileHeader->ntoc) + { + _XcursorFileHeaderDestroy(fileHeader); + return NULL; + } + return fileHeader; } static bool @@ -352,94 +352,94 @@ _XcursorSeekToToc(XcursorFile *file, XcursorFileHeader *fileHeader, int toc) { - if (!file || !fileHeader || \ - (*file->seek)(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) - return false; - return true; + if (!file || !fileHeader || + (*file->seek)(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) + return false; + return true; } static bool _XcursorFileReadChunkHeader(XcursorFile *file, - XcursorFileHeader *fileHeader, - int toc, - XcursorChunkHeader *chunkHeader) + XcursorFileHeader *fileHeader, + int toc, + XcursorChunkHeader *chunkHeader) { - if (!file || !fileHeader || !chunkHeader) - return false; - if (!_XcursorSeekToToc(file, fileHeader, toc)) - return false; - if (!_XcursorReadUInt(file, &chunkHeader->header)) - return false; - if (!_XcursorReadUInt(file, &chunkHeader->type)) - return false; - if (!_XcursorReadUInt(file, &chunkHeader->subtype)) - return false; - if (!_XcursorReadUInt(file, &chunkHeader->version)) - return false; - /* sanity check */ - if (chunkHeader->type != fileHeader->tocs[toc].type || - chunkHeader->subtype != fileHeader->tocs[toc].subtype) - return false; - return true; + if (!file || !fileHeader || !chunkHeader) + return false; + if (!_XcursorSeekToToc(file, fileHeader, toc)) + return false; + if (!_XcursorReadUInt(file, &chunkHeader->header)) + return false; + if (!_XcursorReadUInt(file, &chunkHeader->type)) + return false; + if (!_XcursorReadUInt(file, &chunkHeader->subtype)) + return false; + if (!_XcursorReadUInt(file, &chunkHeader->version)) + return false; + /* sanity check */ + if (chunkHeader->type != fileHeader->tocs[toc].type || + chunkHeader->subtype != fileHeader->tocs[toc].subtype) + return false; + return true; } #define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) static uint32_t _XcursorFindBestSize(XcursorFileHeader *fileHeader, - uint32_t size, - int *nsizesp) + uint32_t size, + int *nsizesp) { - unsigned int n; - int nsizes = 0; - uint32_t bestSize = 0; - uint32_t thisSize; + unsigned int n; + int nsizes = 0; + uint32_t bestSize = 0; + uint32_t thisSize; - if (!fileHeader || !nsizesp) - return 0; + if (!fileHeader || !nsizesp) + return 0; - for (n = 0; n < fileHeader->ntoc; n++) - { - if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) - continue; - thisSize = fileHeader->tocs[n].subtype; - if (!bestSize || dist(thisSize, size) < dist(bestSize, size)) + for (n = 0; n < fileHeader->ntoc; n++) { - bestSize = thisSize; - nsizes = 1; + if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) + continue; + thisSize = fileHeader->tocs[n].subtype; + if (!bestSize || dist(thisSize, size) < dist(bestSize, size)) + { + bestSize = thisSize; + nsizes = 1; + } + else if (thisSize == bestSize) + nsizes++; } - else if (thisSize == bestSize) - nsizes++; - } - *nsizesp = nsizes; - return bestSize; + *nsizesp = nsizes; + return bestSize; } static int _XcursorFindImageToc(XcursorFileHeader *fileHeader, - uint32_t size, - int count) + uint32_t size, + int count) { - unsigned int toc; - uint32_t thisSize; + unsigned int toc; + uint32_t thisSize; - if (!fileHeader) - return 0; + if (!fileHeader) + return 0; - for (toc = 0; toc < fileHeader->ntoc; toc++) - { - if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) - continue; - thisSize = fileHeader->tocs[toc].subtype; - if (thisSize != size) - continue; - if (!count) - break; - count--; - } - if (toc == fileHeader->ntoc) - return -1; - return toc; + for (toc = 0; toc < fileHeader->ntoc; toc++) + { + if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) + continue; + thisSize = fileHeader->tocs[toc].subtype; + if (thisSize != size) + continue; + if (!count) + break; + count--; + } + if (toc == fileHeader->ntoc) + return -1; + return toc; } static XcursorImage * @@ -447,147 +447,147 @@ _XcursorReadImage(XcursorFile *file, XcursorFileHeader *fileHeader, int toc) { - XcursorChunkHeader chunkHeader; - XcursorImage head; - XcursorImage *image; - int n; - uint32_t *p; + XcursorChunkHeader chunkHeader; + XcursorImage head; + XcursorImage *image; + int n; + uint32_t *p; - if (!file || !fileHeader) - return NULL; + if (!file || !fileHeader) + return NULL; - if (!_XcursorFileReadChunkHeader(file, fileHeader, toc, &chunkHeader)) - return NULL; - if (!_XcursorReadUInt(file, &head.width)) - return NULL; - if (!_XcursorReadUInt(file, &head.height)) - return NULL; - if (!_XcursorReadUInt(file, &head.xhot)) - return NULL; - if (!_XcursorReadUInt(file, &head.yhot)) - return NULL; - if (!_XcursorReadUInt(file, &head.delay)) - return NULL; - /* sanity check data */ - if (head.width > XCURSOR_IMAGE_MAX_SIZE || - head.height > XCURSOR_IMAGE_MAX_SIZE) - return NULL; - if (head.width == 0 || head.height == 0) - return NULL; - if (head.xhot > head.width || head.yhot > head.height) - return NULL; + if (!_XcursorFileReadChunkHeader(file, fileHeader, toc, &chunkHeader)) + return NULL; + if (!_XcursorReadUInt(file, &head.width)) + return NULL; + if (!_XcursorReadUInt(file, &head.height)) + return NULL; + if (!_XcursorReadUInt(file, &head.xhot)) + return NULL; + if (!_XcursorReadUInt(file, &head.yhot)) + return NULL; + if (!_XcursorReadUInt(file, &head.delay)) + return NULL; + /* sanity check data */ + if (head.width > XCURSOR_IMAGE_MAX_SIZE || + head.height > XCURSOR_IMAGE_MAX_SIZE) + return NULL; + if (head.width == 0 || head.height == 0) + return NULL; + if (head.xhot > head.width || head.yhot > head.height) + return NULL; - /* Create the image and initialize it */ - image = XcursorImageCreate(head.width, head.height); - if (image == NULL) - return NULL; - if (chunkHeader.version < image->version) - image->version = chunkHeader.version; - image->size = chunkHeader.subtype; - image->xhot = head.xhot; - image->yhot = head.yhot; - image->delay = head.delay; - n = image->width * image->height; - p = image->pixels; - while (n--) - { - if (!_XcursorReadUInt(file, p)) + /* Create the image and initialize it */ + image = XcursorImageCreate(head.width, head.height); + if (image == NULL) + return NULL; + if (chunkHeader.version < image->version) + image->version = chunkHeader.version; + image->size = chunkHeader.subtype; + image->xhot = head.xhot; + image->yhot = head.yhot; + image->delay = head.delay; + n = image->width * image->height; + p = image->pixels; + while (n--) { - XcursorImageDestroy(image); - return NULL; + if (!_XcursorReadUInt(file, p)) + { + XcursorImageDestroy(image); + return NULL; + } + p++; } - p++; - } - return image; + return image; } static XcursorImages * XcursorXcFileLoadImages(XcursorFile *file, int size) { - XcursorFileHeader *fileHeader; - uint32_t bestSize; - int nsize; - XcursorImages *images; - int n; - int toc; + XcursorFileHeader *fileHeader; + uint32_t bestSize; + int nsize; + XcursorImages *images; + int n; + int toc; - if (!file || size < 0) - return NULL; - fileHeader = _XcursorReadFileHeader(file); - if (!fileHeader) - return NULL; - bestSize = _XcursorFindBestSize(fileHeader, (uint32_t) size, &nsize); - if (!bestSize) - { - _XcursorFileHeaderDestroy(fileHeader); - return NULL; - } - images = XcursorImagesCreate(nsize); - if (!images) - { - _XcursorFileHeaderDestroy(fileHeader); - return NULL; - } - for (n = 0; n < nsize; n++) - { - toc = _XcursorFindImageToc(fileHeader, bestSize, n); - if (toc < 0) - break; - images->images[images->nimage] = _XcursorReadImage(file, fileHeader, - toc); - if (!images->images[images->nimage]) - break; - images->nimage++; - } - _XcursorFileHeaderDestroy(fileHeader); - if (images->nimage != nsize) - { - XcursorImagesDestroy(images); - images = NULL; - } - return images; + if (!file || size < 0) + return NULL; + fileHeader = _XcursorReadFileHeader(file); + if (!fileHeader) + return NULL; + bestSize = _XcursorFindBestSize(fileHeader, (uint32_t) size, &nsize); + if (!bestSize) + { + _XcursorFileHeaderDestroy(fileHeader); + return NULL; + } + images = XcursorImagesCreate(nsize); + if (!images) + { + _XcursorFileHeaderDestroy(fileHeader); + return NULL; + } + for (n = 0; n < nsize; n++) + { + toc = _XcursorFindImageToc(fileHeader, bestSize, n); + if (toc < 0) + break; + images->images[images->nimage] = _XcursorReadImage(file, fileHeader, + toc); + if (!images->images[images->nimage]) + break; + images->nimage++; + } + _XcursorFileHeaderDestroy(fileHeader); + if (images->nimage != nsize) + { + XcursorImagesDestroy(images); + images = NULL; + } + return images; } static int _XcursorStdioFileRead(XcursorFile *file, unsigned char *buf, int len) { - FILE *f = file->closure; - return fread(buf, 1, len, f); + FILE *f = file->closure; + return fread(buf, 1, len, f); } static int _XcursorStdioFileWrite(XcursorFile *file, unsigned char *buf, int len) { - FILE *f = file->closure; - return fwrite(buf, 1, len, f); + FILE *f = file->closure; + return fwrite(buf, 1, len, f); } static int _XcursorStdioFileSeek(XcursorFile *file, long offset, int whence) { - FILE *f = file->closure; - return fseek(f, offset, whence); + FILE *f = file->closure; + return fseek(f, offset, whence); } static void _XcursorStdioFileInitialize(FILE *stdfile, XcursorFile *file) { - file->closure = stdfile; - file->read = _XcursorStdioFileRead; - file->write = _XcursorStdioFileWrite; - file->seek = _XcursorStdioFileSeek; + file->closure = stdfile; + file->read = _XcursorStdioFileRead; + file->write = _XcursorStdioFileWrite; + file->seek = _XcursorStdioFileSeek; } static XcursorImages * XcursorFileLoadImages(FILE *file, int size) { - XcursorFile f; + XcursorFile f; - if (!file) - return NULL; + if (!file) + return NULL; - _XcursorStdioFileInitialize(file, &f); - return XcursorXcFileLoadImages(&f, size); + _XcursorStdioFileInitialize(file, &f); + return XcursorXcFileLoadImages(&f, size); } /* @@ -617,138 +617,138 @@ XcursorFileLoadImages(FILE *file, int size) static char * XcursorLibraryPath(void) { - const char *env_var; - char *path = NULL; - int pathlen = 0; + const char *env_var; + char *path = NULL; + int pathlen = 0; - env_var = getenv("XCURSOR_PATH"); - if (env_var) - { - path = strdup(env_var); - } - else - { - env_var = getenv("XDG_DATA_HOME"); - if (env_var) { - pathlen = strlen(env_var) + strlen(CURSORDIR ":" XCURSORPATH) + 1; - path = malloc(pathlen); - snprintf(path, pathlen, "%s%s", env_var, - CURSORDIR ":" XCURSORPATH); + env_var = getenv("XCURSOR_PATH"); + if (env_var) + { + path = strdup(env_var); } else { - path = strdup(XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); + env_var = getenv("XDG_DATA_HOME"); + if (env_var) { + pathlen = strlen(env_var) + strlen(CURSORDIR ":" XCURSORPATH) + 1; + path = malloc(pathlen); + snprintf(path, pathlen, "%s%s", env_var, + CURSORDIR ":" XCURSORPATH); + } + else + { + path = strdup(XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); + } } - } - return path; + return path; } static void _XcursorAddPathElt(char *path, const char *elt, int len) { - int pathlen = strlen(path); + int pathlen = strlen(path); - /* append / if the path doesn't currently have one */ - if (path[0] == '\0' || path[pathlen - 1] != '/') - { - strcat(path, "/"); - pathlen++; - } - if (len == -1) - len = strlen(elt); - /* strip leading slashes */ - while (len && elt[0] == '/') - { - elt++; - len--; - } - strncpy(path + pathlen, elt, len); - path[pathlen + len] = '\0'; + /* append / if the path doesn't currently have one */ + if (path[0] == '\0' || path[pathlen - 1] != '/') + { + strcat(path, "/"); + pathlen++; + } + if (len == -1) + len = strlen(elt); + /* strip leading slashes */ + while (len && elt[0] == '/') + { + elt++; + len--; + } + strncpy(path + pathlen, elt, len); + path[pathlen + len] = '\0'; } static char * _XcursorBuildThemeDir(const char *dir, const char *theme) { - const char *colon; - const char *tcolon; - char *full; - char *home; - int dirlen; - int homelen; - int themelen; - int len; + const char *colon; + const char *tcolon; + char *full; + char *home; + int dirlen; + int homelen; + int themelen; + int len; - if (!dir || !theme) - return NULL; + if (!dir || !theme) + return NULL; - colon = strchr(dir, ':'); - if (!colon) - colon = dir + strlen(dir); + colon = strchr(dir, ':'); + if (!colon) + colon = dir + strlen(dir); - dirlen = colon - dir; + dirlen = colon - dir; - tcolon = strchr(theme, ':'); - if (!tcolon) - tcolon = theme + strlen(theme); + tcolon = strchr(theme, ':'); + if (!tcolon) + tcolon = theme + strlen(theme); - themelen = tcolon - theme; + themelen = tcolon - theme; - home = NULL; - homelen = 0; - if (*dir == '~') - { - home = getenv("HOME"); - if (!home) - return NULL; - homelen = strlen(home); - dir++; - dirlen--; - } + home = NULL; + homelen = 0; + if (*dir == '~') + { + home = getenv("HOME"); + if (!home) + return NULL; + homelen = strlen(home); + dir++; + dirlen--; + } - /* - * add space for any needed directory separators, one per component, - * and one for the trailing null - */ - len = 1 + homelen + 1 + dirlen + 1 + themelen + 1; + /* + * add space for any needed directory separators, one per component, + * and one for the trailing null + */ + len = 1 + homelen + 1 + dirlen + 1 + themelen + 1; - full = malloc(len); - if (!full) - return NULL; - full[0] = '\0'; + full = malloc(len); + if (!full) + return NULL; + full[0] = '\0'; - if (home) - _XcursorAddPathElt(full, home, -1); - _XcursorAddPathElt(full, dir, dirlen); - _XcursorAddPathElt(full, theme, themelen); - return full; + if (home) + _XcursorAddPathElt(full, home, -1); + _XcursorAddPathElt(full, dir, dirlen); + _XcursorAddPathElt(full, theme, themelen); + return full; } static char * _XcursorBuildFullname(const char *dir, const char *subdir, const char *file) { - char *full; + char *full; - if (!dir || !subdir || !file) - return NULL; + if (!dir || !subdir || !file) + return NULL; - full = malloc(strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1); - if (!full) - return NULL; - full[0] = '\0'; - _XcursorAddPathElt(full, dir, -1); - _XcursorAddPathElt(full, subdir, -1); - _XcursorAddPathElt(full, file, -1); - return full; + full = malloc(strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1); + if (!full) + return NULL; + full[0] = '\0'; + _XcursorAddPathElt(full, dir, -1); + _XcursorAddPathElt(full, subdir, -1); + _XcursorAddPathElt(full, file, -1); + return full; } static const char * _XcursorNextPath(const char *path) { - char *colon = strchr(path, ':'); + char *colon = strchr(path, ':'); - if (!colon) - return NULL; - return colon + 1; + if (!colon) + return NULL; + return colon + 1; } #define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') @@ -757,49 +757,49 @@ _XcursorNextPath(const char *path) static char * _XcursorThemeInherits(const char *full) { - char line[8192]; - char *result = NULL; - FILE *f; + char line[8192]; + char *result = NULL; + FILE *f; - if (!full) - return NULL; + if (!full) + return NULL; - f = fopen(full, "r"); - if (f) - { - while (fgets(line, sizeof(line), f)) + f = fopen(full, "r"); + if (f) { - if (!strncmp(line, "Inherits", 8)) - { - char *l = line + 8; - char *r; - while (*l == ' ') l++; - if (*l != '=') continue; - l++; - while (*l == ' ') l++; - result = malloc(strlen(l) + 1); - if (result) + while (fgets(line, sizeof(line), f)) { - r = result; - while (*l) - { - while (XcursorSep(*l) || XcursorWhite(*l)) l++; - if (!*l) - break; - if (r != result) - *r++ = ':'; - while (*l && !XcursorWhite(*l) && - !XcursorSep(*l)) - *r++ = *l++; - } - *r++ = '\0'; + if (!strncmp(line, "Inherits", 8)) + { + char *l = line + 8; + char *r; + while (*l == ' ') l++; + if (*l != '=') continue; + l++; + while (*l == ' ') l++; + result = malloc(strlen(l) + 1); + if (result) + { + r = result; + while (*l) + { + while (XcursorSep(*l) || XcursorWhite(*l)) l++; + if (!*l) + break; + if (r != result) + *r++ = ':'; + while (*l && !XcursorWhite(*l) && + !XcursorSep(*l)) + *r++ = *l++; + } + *r++ = '\0'; + } + break; + } } - break; - } + fclose(f); } - fclose(f); - } - return result; + return result; } static void @@ -819,7 +819,7 @@ load_all_cursors_from_dir(const char *path, int size, for(ent = readdir(dir); ent; ent = readdir(dir)) { #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type != DT_UNKNOWN && - (ent->d_type != DT_REG && ent->d_type != DT_LNK)) + (ent->d_type != DT_REG && ent->d_type != DT_LNK)) continue; #endif @@ -868,8 +868,8 @@ load_all_cursors_from_dir(const char *path, int size, */ void xcursor_load_theme(const char *theme, int size, - void (*load_callback)(XcursorImages *, void *), - void *user_data) + void (*load_callback)(XcursorImages *, void *), + void *user_data) { char *full, *dir; char *inherits = NULL; From 21394fd5f77dc84eb3bcf3ba3fcd74e69393d610 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:17:12 +0200 Subject: [PATCH 0836/1152] cursor: fix spacing around conditions and loops Signed-off-by: Simon Ser --- cursor/xcursor.c | 86 +++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index acf58b14..4cbdead2 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -330,8 +330,7 @@ _XcursorReadFileHeader(XcursorFile *file) fileHeader->header = head.header; fileHeader->version = head.version; fileHeader->ntoc = head.ntoc; - for (n = 0; n < fileHeader->ntoc; n++) - { + for (n = 0; n < fileHeader->ntoc; n++) { if (!_XcursorReadUInt(file, &fileHeader->tocs[n].type)) break; if (!_XcursorReadUInt(file, &fileHeader->tocs[n].subtype)) @@ -339,8 +338,7 @@ _XcursorReadFileHeader(XcursorFile *file) if (!_XcursorReadUInt(file, &fileHeader->tocs[n].position)) break; } - if (n != fileHeader->ntoc) - { + if (n != fileHeader->ntoc) { _XcursorFileHeaderDestroy(fileHeader); return NULL; } @@ -398,18 +396,16 @@ _XcursorFindBestSize(XcursorFileHeader *fileHeader, if (!fileHeader || !nsizesp) return 0; - for (n = 0; n < fileHeader->ntoc; n++) - { + for (n = 0; n < fileHeader->ntoc; n++) { if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) continue; thisSize = fileHeader->tocs[n].subtype; - if (!bestSize || dist(thisSize, size) < dist(bestSize, size)) - { + if (!bestSize || dist(thisSize, size) < dist(bestSize, size)) { bestSize = thisSize; nsizes = 1; - } - else if (thisSize == bestSize) + } else if (thisSize == bestSize) { nsizes++; + } } *nsizesp = nsizes; return bestSize; @@ -426,8 +422,7 @@ _XcursorFindImageToc(XcursorFileHeader *fileHeader, if (!fileHeader) return 0; - for (toc = 0; toc < fileHeader->ntoc; toc++) - { + for (toc = 0; toc < fileHeader->ntoc; toc++) { if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) continue; thisSize = fileHeader->tocs[toc].subtype; @@ -489,10 +484,8 @@ _XcursorReadImage(XcursorFile *file, image->delay = head.delay; n = image->width * image->height; p = image->pixels; - while (n--) - { - if (!_XcursorReadUInt(file, p)) - { + while (n--) { + if (!_XcursorReadUInt(file, p)) { XcursorImageDestroy(image); return NULL; } @@ -517,19 +510,16 @@ XcursorXcFileLoadImages(XcursorFile *file, int size) if (!fileHeader) return NULL; bestSize = _XcursorFindBestSize(fileHeader, (uint32_t) size, &nsize); - if (!bestSize) - { + if (!bestSize) { _XcursorFileHeaderDestroy(fileHeader); return NULL; } images = XcursorImagesCreate(nsize); - if (!images) - { + if (!images) { _XcursorFileHeaderDestroy(fileHeader); return NULL; } - for (n = 0; n < nsize; n++) - { + for (n = 0; n < nsize; n++) { toc = _XcursorFindImageToc(fileHeader, bestSize, n); if (toc < 0) break; @@ -540,8 +530,7 @@ XcursorXcFileLoadImages(XcursorFile *file, int size) images->nimage++; } _XcursorFileHeaderDestroy(fileHeader); - if (images->nimage != nsize) - { + if (images->nimage != nsize) { XcursorImagesDestroy(images); images = NULL; } @@ -622,21 +611,16 @@ XcursorLibraryPath(void) int pathlen = 0; env_var = getenv("XCURSOR_PATH"); - if (env_var) - { + if (env_var) { path = strdup(env_var); - } - else - { + } else { env_var = getenv("XDG_DATA_HOME"); if (env_var) { pathlen = strlen(env_var) + strlen(CURSORDIR ":" XCURSORPATH) + 1; path = malloc(pathlen); snprintf(path, pathlen, "%s%s", env_var, CURSORDIR ":" XCURSORPATH); - } - else - { + } else { path = strdup(XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); } } @@ -649,16 +633,14 @@ _XcursorAddPathElt(char *path, const char *elt, int len) int pathlen = strlen(path); /* append / if the path doesn't currently have one */ - if (path[0] == '\0' || path[pathlen - 1] != '/') - { + if (path[0] == '\0' || path[pathlen - 1] != '/') { strcat(path, "/"); pathlen++; } if (len == -1) len = strlen(elt); /* strip leading slashes */ - while (len && elt[0] == '/') - { + while (len && elt[0] == '/') { elt++; len--; } @@ -695,8 +677,7 @@ _XcursorBuildThemeDir(const char *dir, const char *theme) home = NULL; homelen = 0; - if (*dir == '~') - { + if (*dir == '~') { home = getenv("HOME"); if (!home) return NULL; @@ -765,25 +746,24 @@ _XcursorThemeInherits(const char *full) return NULL; f = fopen(full, "r"); - if (f) - { - while (fgets(line, sizeof(line), f)) - { - if (!strncmp(line, "Inherits", 8)) - { + if (f) { + while (fgets(line, sizeof(line), f)) { + if (!strncmp(line, "Inherits", 8)) { char *l = line + 8; char *r; - while (*l == ' ') l++; - if (*l != '=') continue; + while (*l == ' ') + l++; + if (*l != '=') + continue; l++; - while (*l == ' ') l++; + while (*l == ' ') + l++; result = malloc(strlen(l) + 1); - if (result) - { + if (result) { r = result; - while (*l) - { - while (XcursorSep(*l) || XcursorWhite(*l)) l++; + while (*l) { + while (XcursorSep(*l) || XcursorWhite(*l)) + l++; if (!*l) break; if (r != result) @@ -816,7 +796,7 @@ load_all_cursors_from_dir(const char *path, int size, if (!dir) return; - for(ent = readdir(dir); ent; ent = readdir(dir)) { + for (ent = readdir(dir); ent; ent = readdir(dir)) { #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type != DT_UNKNOWN && (ent->d_type != DT_REG && ent->d_type != DT_LNK)) From a46d8be4e1e8d3fc9920e280282b0e32054e6d02 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:29:08 +0200 Subject: [PATCH 0837/1152] cursor: remove struct typedefs, rename to snake case Signed-off-by: Simon Ser --- cursor/wayland-cursor.c | 4 +- cursor/xcursor.c | 136 ++++++++++++++++++++-------------------- cursor/xcursor.h | 14 ++--- 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 3501088a..7ba5eb6d 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -274,7 +274,7 @@ load_fallback_theme(struct wl_cursor_theme *theme) } static struct wl_cursor * -wl_cursor_create_from_xcursor_images(XcursorImages *images, +wl_cursor_create_from_xcursor_images(struct xcursor_images *images, struct wl_cursor_theme *theme) { struct cursor *cursor; @@ -335,7 +335,7 @@ wl_cursor_create_from_xcursor_images(XcursorImages *images, } static void -load_callback(XcursorImages *images, void *data) +load_callback(struct xcursor_images *images, void *data) { struct wl_cursor_theme *theme = data; struct wl_cursor *cursor; diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 4cbdead2..84661830 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -74,19 +74,19 @@ #define XCURSOR_FILE_HEADER_LEN (4 * 4) #define XCURSOR_FILE_TOC_LEN (3 * 4) -typedef struct _XcursorFileToc { +struct xcursor_file_toc { uint32_t type; /* chunk type */ uint32_t subtype; /* subtype (size for images) */ uint32_t position; /* absolute position in file */ -} XcursorFileToc; +}; -typedef struct _XcursorFileHeader { +struct xcursor_file_header { uint32_t magic; /* magic number */ uint32_t header; /* byte length of header */ uint32_t version; /* file version number */ uint32_t ntoc; /* number of toc entries */ - XcursorFileToc *tocs; /* table of contents */ -} XcursorFileHeader; + struct xcursor_file_toc *tocs; /* table of contents */ +}; /* * The rest of the file is a list of chunks, each tagged by type @@ -106,12 +106,12 @@ typedef struct _XcursorFileHeader { #define XCURSOR_CHUNK_HEADER_LEN (4 * 4) -typedef struct _XcursorChunkHeader { +struct xcursor_chunk_header { uint32_t header; /* bytes in chunk header */ uint32_t type; /* chunk type */ uint32_t subtype; /* chunk subtype (size for images) */ uint32_t version; /* version of this type */ -} XcursorChunkHeader; +}; /* * Here's a list of the known chunk types @@ -135,11 +135,11 @@ typedef struct _XcursorChunkHeader { #define XCURSOR_COMMENT_OTHER 3 #define XCURSOR_COMMENT_MAX_LEN 0x100000 -typedef struct _XcursorComment { +struct xcursor_comment { uint32_t version; uint32_t comment_type; char *comment; -} XcursorComment; +}; /* * Each cursor image occupies a separate image chunk. @@ -162,35 +162,33 @@ typedef struct _XcursorComment { #define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) #define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ -typedef struct _XcursorFile XcursorFile; - -struct _XcursorFile { +struct xcursor_file { void *closure; - int (*read)(XcursorFile *file, unsigned char *buf, int len); - int (*write)(XcursorFile *file, unsigned char *buf, int len); - int (*seek)(XcursorFile *file, long offset, int whence); + int (*read)(struct xcursor_file *file, unsigned char *buf, int len); + int (*write)(struct xcursor_file *file, unsigned char *buf, int len); + int (*seek)(struct xcursor_file *file, long offset, int whence); }; -typedef struct _XcursorComments { +struct xcursor_comments { int ncomment; /* number of comments */ - XcursorComment **comments; /* array of XcursorComment pointers */ -} XcursorComments; + struct xcursor_comments **comments; /* array of XcursorComment pointers */ +}; /* * From libXcursor/src/file.c */ -static XcursorImage * +static struct xcursor_image * XcursorImageCreate(int width, int height) { - XcursorImage *image; + struct xcursor_image *image; if (width < 0 || height < 0) return NULL; if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) return NULL; - image = malloc(sizeof(XcursorImage) + + image = malloc(sizeof(struct xcursor_image) + width * height * sizeof(uint32_t)); if (!image) return NULL; @@ -204,28 +202,28 @@ XcursorImageCreate(int width, int height) } static void -XcursorImageDestroy(XcursorImage *image) +XcursorImageDestroy(struct xcursor_image *image) { free(image); } -static XcursorImages * +static struct xcursor_images * XcursorImagesCreate(int size) { - XcursorImages *images; + struct xcursor_images *images; - images = malloc(sizeof(XcursorImages) + - size * sizeof(XcursorImage *)); + images = malloc(sizeof(struct xcursor_images) + + size * sizeof(struct xcursor_image *)); if (!images) return NULL; images->nimage = 0; - images->images = (XcursorImage **) (images + 1); + images->images = (struct xcursor_image **) (images + 1); images->name = NULL; return images; } void -XcursorImagesDestroy(XcursorImages *images) +XcursorImagesDestroy(struct xcursor_images *images) { int n; @@ -239,7 +237,7 @@ XcursorImagesDestroy(XcursorImages *images) } static void -XcursorImagesSetName(XcursorImages *images, const char *name) +XcursorImagesSetName(struct xcursor_images *images, const char *name) { char *new; @@ -257,7 +255,7 @@ XcursorImagesSetName(XcursorImages *images, const char *name) } static bool -_XcursorReadUInt(XcursorFile *file, uint32_t *u) +_XcursorReadUInt(struct xcursor_file *file, uint32_t *u) { unsigned char bytes[4]; @@ -275,34 +273,34 @@ _XcursorReadUInt(XcursorFile *file, uint32_t *u) } static void -_XcursorFileHeaderDestroy(XcursorFileHeader *fileHeader) +_XcursorFileHeaderDestroy(struct xcursor_file_header *fileHeader) { free(fileHeader); } -static XcursorFileHeader * +static struct xcursor_file_header * _XcursorFileHeaderCreate(uint32_t ntoc) { - XcursorFileHeader *fileHeader; + struct xcursor_file_header *fileHeader; if (ntoc > 0x10000) return NULL; - fileHeader = malloc(sizeof(XcursorFileHeader) + - ntoc * sizeof(XcursorFileToc)); + fileHeader = malloc(sizeof(struct xcursor_file_header) + + ntoc * sizeof(struct xcursor_file_toc)); if (!fileHeader) return NULL; fileHeader->magic = XCURSOR_MAGIC; fileHeader->header = XCURSOR_FILE_HEADER_LEN; fileHeader->version = XCURSOR_FILE_VERSION; fileHeader->ntoc = ntoc; - fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); + fileHeader->tocs = (struct xcursor_file_toc *) (fileHeader + 1); return fileHeader; } -static XcursorFileHeader * -_XcursorReadFileHeader(XcursorFile *file) +static struct xcursor_file_header * +_XcursorReadFileHeader(struct xcursor_file *file) { - XcursorFileHeader head, *fileHeader; + struct xcursor_file_header head, *fileHeader; uint32_t skip; unsigned int n; @@ -346,8 +344,8 @@ _XcursorReadFileHeader(XcursorFile *file) } static bool -_XcursorSeekToToc(XcursorFile *file, - XcursorFileHeader *fileHeader, +_XcursorSeekToToc(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, int toc) { if (!file || !fileHeader || @@ -357,10 +355,10 @@ _XcursorSeekToToc(XcursorFile *file, } static bool -_XcursorFileReadChunkHeader(XcursorFile *file, - XcursorFileHeader *fileHeader, +_XcursorFileReadChunkHeader(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, int toc, - XcursorChunkHeader *chunkHeader) + struct xcursor_chunk_header *chunkHeader) { if (!file || !fileHeader || !chunkHeader) return false; @@ -384,7 +382,7 @@ _XcursorFileReadChunkHeader(XcursorFile *file, #define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) static uint32_t -_XcursorFindBestSize(XcursorFileHeader *fileHeader, +_XcursorFindBestSize(struct xcursor_file_header *fileHeader, uint32_t size, int *nsizesp) { @@ -412,7 +410,7 @@ _XcursorFindBestSize(XcursorFileHeader *fileHeader, } static int -_XcursorFindImageToc(XcursorFileHeader *fileHeader, +_XcursorFindImageToc(struct xcursor_file_header *fileHeader, uint32_t size, int count) { @@ -437,14 +435,14 @@ _XcursorFindImageToc(XcursorFileHeader *fileHeader, return toc; } -static XcursorImage * -_XcursorReadImage(XcursorFile *file, - XcursorFileHeader *fileHeader, +static struct xcursor_image * +_XcursorReadImage(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, int toc) { - XcursorChunkHeader chunkHeader; - XcursorImage head; - XcursorImage *image; + struct xcursor_chunk_header chunkHeader; + struct xcursor_image head; + struct xcursor_image *image; int n; uint32_t *p; @@ -494,13 +492,13 @@ _XcursorReadImage(XcursorFile *file, return image; } -static XcursorImages * -XcursorXcFileLoadImages(XcursorFile *file, int size) +static struct xcursor_images * +XcursorXcFileLoadImages(struct xcursor_file *file, int size) { - XcursorFileHeader *fileHeader; + struct xcursor_file_header *fileHeader; uint32_t bestSize; int nsize; - XcursorImages *images; + struct xcursor_images *images; int n; int toc; @@ -538,28 +536,28 @@ XcursorXcFileLoadImages(XcursorFile *file, int size) } static int -_XcursorStdioFileRead(XcursorFile *file, unsigned char *buf, int len) +_XcursorStdioFileRead(struct xcursor_file *file, unsigned char *buf, int len) { FILE *f = file->closure; return fread(buf, 1, len, f); } static int -_XcursorStdioFileWrite(XcursorFile *file, unsigned char *buf, int len) +_XcursorStdioFileWrite(struct xcursor_file *file, unsigned char *buf, int len) { FILE *f = file->closure; return fwrite(buf, 1, len, f); } static int -_XcursorStdioFileSeek(XcursorFile *file, long offset, int whence) +_XcursorStdioFileSeek(struct xcursor_file *file, long offset, int whence) { FILE *f = file->closure; return fseek(f, offset, whence); } static void -_XcursorStdioFileInitialize(FILE *stdfile, XcursorFile *file) +_XcursorStdioFileInitialize(FILE *stdfile, struct xcursor_file *file) { file->closure = stdfile; file->read = _XcursorStdioFileRead; @@ -567,10 +565,10 @@ _XcursorStdioFileInitialize(FILE *stdfile, XcursorFile *file) file->seek = _XcursorStdioFileSeek; } -static XcursorImages * +static struct xcursor_images * XcursorFileLoadImages(FILE *file, int size) { - XcursorFile f; + struct xcursor_file f; if (!file) return NULL; @@ -784,14 +782,14 @@ _XcursorThemeInherits(const char *full) static void load_all_cursors_from_dir(const char *path, int size, - void (*load_callback)(XcursorImages *, void *), + void (*load_callback)(struct xcursor_images *, void *), void *user_data) { FILE *f; DIR *dir = opendir(path); struct dirent *ent; char *full; - XcursorImages *images; + struct xcursor_images *images; if (!dir) return; @@ -830,25 +828,25 @@ load_all_cursors_from_dir(const char *path, int size, /** Load all the cursor of a theme * * This function loads all the cursor images of a given theme and its - * inherited themes. Each cursor is loaded into an XcursorImages object + * inherited themes. Each cursor is loaded into an struct xcursor_images object * which is passed to the caller's load callback. If a cursor appears * more than once across all the inherited themes, the load callback - * will be called multiple times, with possibly different XcursorImages + * will be called multiple times, with possibly different struct xcursor_images * object which have the same name. The user is expected to destroy the - * XcursorImages objects passed to the callback with + * struct xcursor_images objects passed to the callback with * XcursorImagesDestroy(). * * \param theme The name of theme that should be loaded * \param size The desired size of the cursor images * \param load_callback A callback function that will be called - * for each cursor loaded. The first parameter is the XcursorImages + * for each cursor loaded. The first parameter is the struct xcursor_images * object representing the loaded cursor and the second is a pointer * to data provided by the user. * \param user_data The data that should be passed to the load callback */ void xcursor_load_theme(const char *theme, int size, - void (*load_callback)(XcursorImages *, void *), + void (*load_callback)(struct xcursor_images *, void *), void *user_data) { char *full, *dir; diff --git a/cursor/xcursor.h b/cursor/xcursor.h index e417904b..528a1693 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -28,7 +28,7 @@ #include -typedef struct _XcursorImage { +struct xcursor_image { uint32_t version; /* version of the image data */ uint32_t size; /* nominal size for matching */ uint32_t width; /* actual width */ @@ -37,22 +37,22 @@ typedef struct _XcursorImage { uint32_t yhot; /* hot spot y (must be inside image) */ uint32_t delay; /* animation delay to next frame (ms) */ uint32_t *pixels; /* pointer to pixels */ -} XcursorImage; +}; /* * Other data structures exposed by the library API */ -typedef struct _XcursorImages { +struct xcursor_images { int nimage; /* number of images */ - XcursorImage **images; /* array of XcursorImage pointers */ + struct xcursor_image **images; /* array of XcursorImage pointers */ char *name; /* name used to load images */ -} XcursorImages; +}; void -XcursorImagesDestroy(XcursorImages *images); +XcursorImagesDestroy(struct xcursor_images *images); void xcursor_load_theme(const char *theme, int size, - void (*load_callback)(XcursorImages *, void *), + void (*load_callback)(struct xcursor_images *, void *), void *user_data); #endif From 3c12a7a1bef7c9c316925dce55a2dff2df4c87d2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:31:45 +0200 Subject: [PATCH 0838/1152] cursor: fix whitespace in function args definitions Signed-off-by: Simon Ser --- cursor/xcursor.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 84661830..6f3a8c18 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -344,9 +344,9 @@ _XcursorReadFileHeader(struct xcursor_file *file) } static bool -_XcursorSeekToToc(struct xcursor_file *file, - struct xcursor_file_header *fileHeader, - int toc) +_XcursorSeekToToc(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, + int toc) { if (!file || !fileHeader || (*file->seek)(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) @@ -355,10 +355,10 @@ _XcursorSeekToToc(struct xcursor_file *file, } static bool -_XcursorFileReadChunkHeader(struct xcursor_file *file, - struct xcursor_file_header *fileHeader, - int toc, - struct xcursor_chunk_header *chunkHeader) +_XcursorFileReadChunkHeader(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, + int toc, + struct xcursor_chunk_header *chunkHeader) { if (!file || !fileHeader || !chunkHeader) return false; @@ -383,8 +383,7 @@ _XcursorFileReadChunkHeader(struct xcursor_file *file, static uint32_t _XcursorFindBestSize(struct xcursor_file_header *fileHeader, - uint32_t size, - int *nsizesp) + uint32_t size, int *nsizesp) { unsigned int n; int nsizes = 0; @@ -410,9 +409,8 @@ _XcursorFindBestSize(struct xcursor_file_header *fileHeader, } static int -_XcursorFindImageToc(struct xcursor_file_header *fileHeader, - uint32_t size, - int count) +_XcursorFindImageToc(struct xcursor_file_header *fileHeader, + uint32_t size, int count) { unsigned int toc; uint32_t thisSize; @@ -436,9 +434,9 @@ _XcursorFindImageToc(struct xcursor_file_header *fileHeader, } static struct xcursor_image * -_XcursorReadImage(struct xcursor_file *file, - struct xcursor_file_header *fileHeader, - int toc) +_XcursorReadImage(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, + int toc) { struct xcursor_chunk_header chunkHeader; struct xcursor_image head; From bcfcd49232e3881d995da83a15dbc2897148c5fb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:45:20 +0200 Subject: [PATCH 0839/1152] cursor: rename functions to snake case Signed-off-by: Simon Ser --- cursor/wayland-cursor.c | 4 +- cursor/xcursor.c | 192 ++++++++++++++++++++-------------------- cursor/xcursor.h | 2 +- 3 files changed, 99 insertions(+), 99 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 7ba5eb6d..3518aa44 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -341,7 +341,7 @@ load_callback(struct xcursor_images *images, void *data) struct wl_cursor *cursor; if (wl_cursor_theme_get_cursor(theme, images->name)) { - XcursorImagesDestroy(images); + xcursor_images_destroy(images); return; } @@ -361,7 +361,7 @@ load_callback(struct xcursor_images *images, void *data) } } - XcursorImagesDestroy(images); + xcursor_images_destroy(images); } /** Load a cursor theme to memory shared with the compositor diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 6f3a8c18..e4b9a9d1 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -179,7 +179,7 @@ struct xcursor_comments { */ static struct xcursor_image * -XcursorImageCreate(int width, int height) +xcursor_image_create(int width, int height) { struct xcursor_image *image; @@ -202,13 +202,13 @@ XcursorImageCreate(int width, int height) } static void -XcursorImageDestroy(struct xcursor_image *image) +xcursor_image_destroy(struct xcursor_image *image) { free(image); } static struct xcursor_images * -XcursorImagesCreate(int size) +xcursor_images_create(int size) { struct xcursor_images *images; @@ -223,7 +223,7 @@ XcursorImagesCreate(int size) } void -XcursorImagesDestroy(struct xcursor_images *images) +xcursor_images_destroy(struct xcursor_images *images) { int n; @@ -231,13 +231,13 @@ XcursorImagesDestroy(struct xcursor_images *images) return; for (n = 0; n < images->nimage; n++) - XcursorImageDestroy(images->images[n]); + xcursor_image_destroy(images->images[n]); free(images->name); free(images); } static void -XcursorImagesSetName(struct xcursor_images *images, const char *name) +xcursor_images_set_name(struct xcursor_images *images, const char *name) { char *new; @@ -255,7 +255,7 @@ XcursorImagesSetName(struct xcursor_images *images, const char *name) } static bool -_XcursorReadUInt(struct xcursor_file *file, uint32_t *u) +xcursor_read_uint(struct xcursor_file *file, uint32_t *u) { unsigned char bytes[4]; @@ -273,13 +273,13 @@ _XcursorReadUInt(struct xcursor_file *file, uint32_t *u) } static void -_XcursorFileHeaderDestroy(struct xcursor_file_header *fileHeader) +xcursor_file_header_destroy(struct xcursor_file_header *fileHeader) { free(fileHeader); } static struct xcursor_file_header * -_XcursorFileHeaderCreate(uint32_t ntoc) +xcursor_file_header_create(uint32_t ntoc) { struct xcursor_file_header *fileHeader; @@ -298,7 +298,7 @@ _XcursorFileHeaderCreate(uint32_t ntoc) } static struct xcursor_file_header * -_XcursorReadFileHeader(struct xcursor_file *file) +xcursor_read_file_header(struct xcursor_file *file) { struct xcursor_file_header head, *fileHeader; uint32_t skip; @@ -307,21 +307,21 @@ _XcursorReadFileHeader(struct xcursor_file *file) if (!file) return NULL; - if (!_XcursorReadUInt(file, &head.magic)) + if (!xcursor_read_uint(file, &head.magic)) return NULL; if (head.magic != XCURSOR_MAGIC) return NULL; - if (!_XcursorReadUInt(file, &head.header)) + if (!xcursor_read_uint(file, &head.header)) return NULL; - if (!_XcursorReadUInt(file, &head.version)) + if (!xcursor_read_uint(file, &head.version)) return NULL; - if (!_XcursorReadUInt(file, &head.ntoc)) + if (!xcursor_read_uint(file, &head.ntoc)) return NULL; skip = head.header - XCURSOR_FILE_HEADER_LEN; if (skip) if ((*file->seek)(file, skip, SEEK_CUR) == EOF) return NULL; - fileHeader = _XcursorFileHeaderCreate(head.ntoc); + fileHeader = xcursor_file_header_create(head.ntoc); if (!fileHeader) return NULL; fileHeader->magic = head.magic; @@ -329,24 +329,24 @@ _XcursorReadFileHeader(struct xcursor_file *file) fileHeader->version = head.version; fileHeader->ntoc = head.ntoc; for (n = 0; n < fileHeader->ntoc; n++) { - if (!_XcursorReadUInt(file, &fileHeader->tocs[n].type)) + if (!xcursor_read_uint(file, &fileHeader->tocs[n].type)) break; - if (!_XcursorReadUInt(file, &fileHeader->tocs[n].subtype)) + if (!xcursor_read_uint(file, &fileHeader->tocs[n].subtype)) break; - if (!_XcursorReadUInt(file, &fileHeader->tocs[n].position)) + if (!xcursor_read_uint(file, &fileHeader->tocs[n].position)) break; } if (n != fileHeader->ntoc) { - _XcursorFileHeaderDestroy(fileHeader); + xcursor_file_header_destroy(fileHeader); return NULL; } return fileHeader; } static bool -_XcursorSeekToToc(struct xcursor_file *file, - struct xcursor_file_header *fileHeader, - int toc) +xcursor_seek_to_toc(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, + int toc) { if (!file || !fileHeader || (*file->seek)(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) @@ -355,22 +355,22 @@ _XcursorSeekToToc(struct xcursor_file *file, } static bool -_XcursorFileReadChunkHeader(struct xcursor_file *file, - struct xcursor_file_header *fileHeader, - int toc, - struct xcursor_chunk_header *chunkHeader) +xcursor_file_read_chunk_header(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, + int toc, + struct xcursor_chunk_header *chunkHeader) { if (!file || !fileHeader || !chunkHeader) return false; - if (!_XcursorSeekToToc(file, fileHeader, toc)) + if (!xcursor_seek_to_toc(file, fileHeader, toc)) return false; - if (!_XcursorReadUInt(file, &chunkHeader->header)) + if (!xcursor_read_uint(file, &chunkHeader->header)) return false; - if (!_XcursorReadUInt(file, &chunkHeader->type)) + if (!xcursor_read_uint(file, &chunkHeader->type)) return false; - if (!_XcursorReadUInt(file, &chunkHeader->subtype)) + if (!xcursor_read_uint(file, &chunkHeader->subtype)) return false; - if (!_XcursorReadUInt(file, &chunkHeader->version)) + if (!xcursor_read_uint(file, &chunkHeader->version)) return false; /* sanity check */ if (chunkHeader->type != fileHeader->tocs[toc].type || @@ -382,8 +382,8 @@ _XcursorFileReadChunkHeader(struct xcursor_file *file, #define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) static uint32_t -_XcursorFindBestSize(struct xcursor_file_header *fileHeader, - uint32_t size, int *nsizesp) +xcursor_file_best_size(struct xcursor_file_header *fileHeader, + uint32_t size, int *nsizesp) { unsigned int n; int nsizes = 0; @@ -409,8 +409,8 @@ _XcursorFindBestSize(struct xcursor_file_header *fileHeader, } static int -_XcursorFindImageToc(struct xcursor_file_header *fileHeader, - uint32_t size, int count) +xcursor_find_image_toc(struct xcursor_file_header *fileHeader, + uint32_t size, int count) { unsigned int toc; uint32_t thisSize; @@ -434,9 +434,9 @@ _XcursorFindImageToc(struct xcursor_file_header *fileHeader, } static struct xcursor_image * -_XcursorReadImage(struct xcursor_file *file, - struct xcursor_file_header *fileHeader, - int toc) +xcursor_read_image(struct xcursor_file *file, + struct xcursor_file_header *fileHeader, + int toc) { struct xcursor_chunk_header chunkHeader; struct xcursor_image head; @@ -447,17 +447,17 @@ _XcursorReadImage(struct xcursor_file *file, if (!file || !fileHeader) return NULL; - if (!_XcursorFileReadChunkHeader(file, fileHeader, toc, &chunkHeader)) + if (!xcursor_file_read_chunk_header(file, fileHeader, toc, &chunkHeader)) return NULL; - if (!_XcursorReadUInt(file, &head.width)) + if (!xcursor_read_uint(file, &head.width)) return NULL; - if (!_XcursorReadUInt(file, &head.height)) + if (!xcursor_read_uint(file, &head.height)) return NULL; - if (!_XcursorReadUInt(file, &head.xhot)) + if (!xcursor_read_uint(file, &head.xhot)) return NULL; - if (!_XcursorReadUInt(file, &head.yhot)) + if (!xcursor_read_uint(file, &head.yhot)) return NULL; - if (!_XcursorReadUInt(file, &head.delay)) + if (!xcursor_read_uint(file, &head.delay)) return NULL; /* sanity check data */ if (head.width > XCURSOR_IMAGE_MAX_SIZE || @@ -469,7 +469,7 @@ _XcursorReadImage(struct xcursor_file *file, return NULL; /* Create the image and initialize it */ - image = XcursorImageCreate(head.width, head.height); + image = xcursor_image_create(head.width, head.height); if (image == NULL) return NULL; if (chunkHeader.version < image->version) @@ -481,8 +481,8 @@ _XcursorReadImage(struct xcursor_file *file, n = image->width * image->height; p = image->pixels; while (n--) { - if (!_XcursorReadUInt(file, p)) { - XcursorImageDestroy(image); + if (!xcursor_read_uint(file, p)) { + xcursor_image_destroy(image); return NULL; } p++; @@ -491,7 +491,7 @@ _XcursorReadImage(struct xcursor_file *file, } static struct xcursor_images * -XcursorXcFileLoadImages(struct xcursor_file *file, int size) +xcursor_xc_file_load_images(struct xcursor_file *file, int size) { struct xcursor_file_header *fileHeader; uint32_t bestSize; @@ -502,77 +502,77 @@ XcursorXcFileLoadImages(struct xcursor_file *file, int size) if (!file || size < 0) return NULL; - fileHeader = _XcursorReadFileHeader(file); + fileHeader = xcursor_read_file_header(file); if (!fileHeader) return NULL; - bestSize = _XcursorFindBestSize(fileHeader, (uint32_t) size, &nsize); + bestSize = xcursor_file_best_size(fileHeader, (uint32_t) size, &nsize); if (!bestSize) { - _XcursorFileHeaderDestroy(fileHeader); + xcursor_file_header_destroy(fileHeader); return NULL; } - images = XcursorImagesCreate(nsize); + images = xcursor_images_create(nsize); if (!images) { - _XcursorFileHeaderDestroy(fileHeader); + xcursor_file_header_destroy(fileHeader); return NULL; } for (n = 0; n < nsize; n++) { - toc = _XcursorFindImageToc(fileHeader, bestSize, n); + toc = xcursor_find_image_toc(fileHeader, bestSize, n); if (toc < 0) break; - images->images[images->nimage] = _XcursorReadImage(file, fileHeader, - toc); + images->images[images->nimage] = xcursor_read_image(file, fileHeader, + toc); if (!images->images[images->nimage]) break; images->nimage++; } - _XcursorFileHeaderDestroy(fileHeader); + xcursor_file_header_destroy(fileHeader); if (images->nimage != nsize) { - XcursorImagesDestroy(images); + xcursor_images_destroy(images); images = NULL; } return images; } static int -_XcursorStdioFileRead(struct xcursor_file *file, unsigned char *buf, int len) +xcursor_stdio_file_read(struct xcursor_file *file, unsigned char *buf, int len) { FILE *f = file->closure; return fread(buf, 1, len, f); } static int -_XcursorStdioFileWrite(struct xcursor_file *file, unsigned char *buf, int len) +xcursor_stdio_file_write(struct xcursor_file *file, unsigned char *buf, int len) { FILE *f = file->closure; return fwrite(buf, 1, len, f); } static int -_XcursorStdioFileSeek(struct xcursor_file *file, long offset, int whence) +xcursor_stdio_file_seek(struct xcursor_file *file, long offset, int whence) { FILE *f = file->closure; return fseek(f, offset, whence); } static void -_XcursorStdioFileInitialize(FILE *stdfile, struct xcursor_file *file) +xcursor_stdio_file_initialize(FILE *stdfile, struct xcursor_file *file) { file->closure = stdfile; - file->read = _XcursorStdioFileRead; - file->write = _XcursorStdioFileWrite; - file->seek = _XcursorStdioFileSeek; + file->read = xcursor_stdio_file_read; + file->write = xcursor_stdio_file_write; + file->seek = xcursor_stdio_file_seek; } static struct xcursor_images * -XcursorFileLoadImages(FILE *file, int size) +xcursor_file_load_images(FILE *file, int size) { struct xcursor_file f; if (!file) return NULL; - _XcursorStdioFileInitialize(file, &f); - return XcursorXcFileLoadImages(&f, size); + xcursor_stdio_file_initialize(file, &f); + return xcursor_xc_file_load_images(&f, size); } /* @@ -600,7 +600,7 @@ XcursorFileLoadImages(FILE *file, int size) * and must be freed by the caller. */ static char * -XcursorLibraryPath(void) +xcursor_library_path(void) { const char *env_var; char *path = NULL; @@ -624,7 +624,7 @@ XcursorLibraryPath(void) } static void -_XcursorAddPathElt(char *path, const char *elt, int len) +xcursor_add_path_elt(char *path, const char *elt, int len) { int pathlen = strlen(path); @@ -645,7 +645,7 @@ _XcursorAddPathElt(char *path, const char *elt, int len) } static char * -_XcursorBuildThemeDir(const char *dir, const char *theme) +xcursor_build_theme_dir(const char *dir, const char *theme) { const char *colon; const char *tcolon; @@ -694,14 +694,14 @@ _XcursorBuildThemeDir(const char *dir, const char *theme) full[0] = '\0'; if (home) - _XcursorAddPathElt(full, home, -1); - _XcursorAddPathElt(full, dir, dirlen); - _XcursorAddPathElt(full, theme, themelen); + xcursor_add_path_elt(full, home, -1); + xcursor_add_path_elt(full, dir, dirlen); + xcursor_add_path_elt(full, theme, themelen); return full; } static char * -_XcursorBuildFullname(const char *dir, const char *subdir, const char *file) +xcursor_build_fullname(const char *dir, const char *subdir, const char *file) { char *full; @@ -712,14 +712,14 @@ _XcursorBuildFullname(const char *dir, const char *subdir, const char *file) if (!full) return NULL; full[0] = '\0'; - _XcursorAddPathElt(full, dir, -1); - _XcursorAddPathElt(full, subdir, -1); - _XcursorAddPathElt(full, file, -1); + xcursor_add_path_elt(full, dir, -1); + xcursor_add_path_elt(full, subdir, -1); + xcursor_add_path_elt(full, file, -1); return full; } static const char * -_XcursorNextPath(const char *path) +xcursor_next_path(const char *path) { char *colon = strchr(path, ':'); @@ -728,11 +728,11 @@ _XcursorNextPath(const char *path) return colon + 1; } -#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') -#define XcursorSep(c) ((c) == ';' || (c) == ',') +#define xcursor_white(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define xcursor_sep(c) ((c) == ';' || (c) == ',') static char * -_XcursorThemeInherits(const char *full) +xcursor_theme_inherits(const char *full) { char line[8192]; char *result = NULL; @@ -758,14 +758,14 @@ _XcursorThemeInherits(const char *full) if (result) { r = result; while (*l) { - while (XcursorSep(*l) || XcursorWhite(*l)) + while (xcursor_sep(*l) || xcursor_white(*l)) l++; if (!*l) break; if (r != result) *r++ = ':'; - while (*l && !XcursorWhite(*l) && - !XcursorSep(*l)) + while (*l && !xcursor_white(*l) && + !xcursor_sep(*l)) *r++ = *l++; } *r++ = '\0'; @@ -799,7 +799,7 @@ load_all_cursors_from_dir(const char *path, int size, continue; #endif - full = _XcursorBuildFullname(path, "", ent->d_name); + full = xcursor_build_fullname(path, "", ent->d_name); if (!full) continue; @@ -809,10 +809,10 @@ load_all_cursors_from_dir(const char *path, int size, continue; } - images = XcursorFileLoadImages(f, size); + images = xcursor_file_load_images(f, size); if (images) { - XcursorImagesSetName(images, ent->d_name); + xcursor_images_set_name(images, ent->d_name); load_callback(images, user_data); } @@ -832,7 +832,7 @@ load_all_cursors_from_dir(const char *path, int size, * will be called multiple times, with possibly different struct xcursor_images * object which have the same name. The user is expected to destroy the * struct xcursor_images objects passed to the callback with - * XcursorImagesDestroy(). + * xcursor_images_destroy(). * * \param theme The name of theme that should be loaded * \param size The desired size of the cursor images @@ -855,15 +855,15 @@ xcursor_load_theme(const char *theme, int size, if (!theme) theme = "default"; - xcursor_path = XcursorLibraryPath(); + xcursor_path = xcursor_library_path(); for (path = xcursor_path; path; - path = _XcursorNextPath(path)) { - dir = _XcursorBuildThemeDir(path, theme); + path = xcursor_next_path(path)) { + dir = xcursor_build_theme_dir(path, theme); if (!dir) continue; - full = _XcursorBuildFullname(dir, "cursors", ""); + full = xcursor_build_fullname(dir, "cursors", ""); if (full) { load_all_cursors_from_dir(full, size, load_callback, @@ -872,9 +872,9 @@ xcursor_load_theme(const char *theme, int size, } if (!inherits) { - full = _XcursorBuildFullname(dir, "", "index.theme"); + full = xcursor_build_fullname(dir, "", "index.theme"); if (full) { - inherits = _XcursorThemeInherits(full); + inherits = xcursor_theme_inherits(full); free(full); } } @@ -882,7 +882,7 @@ xcursor_load_theme(const char *theme, int size, free(dir); } - for (i = inherits; i; i = _XcursorNextPath(i)) + for (i = inherits; i; i = xcursor_next_path(i)) xcursor_load_theme(i, size, load_callback, user_data); free(inherits); diff --git a/cursor/xcursor.h b/cursor/xcursor.h index 528a1693..459f8166 100644 --- a/cursor/xcursor.h +++ b/cursor/xcursor.h @@ -49,7 +49,7 @@ struct xcursor_images { }; void -XcursorImagesDestroy(struct xcursor_images *images); +xcursor_images_destroy(struct xcursor_images *images); void xcursor_load_theme(const char *theme, int size, From 963014459c5eb54b1317c688f9e2dfbac44a672d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:48:49 +0200 Subject: [PATCH 0840/1152] cursor: convert macros to functions Improves readability since there's no need for so many parentheses anymore, adds type safety. The compiler will inline the function automatically as necessary. Signed-off-by: Simon Ser --- cursor/xcursor.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index e4b9a9d1..0a7dfecb 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -379,7 +379,11 @@ xcursor_file_read_chunk_header(struct xcursor_file *file, return true; } -#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) +static uint32_t +dist(uint32_t a, uint32_t b) +{ + return a > b ? a - b : b - a; +} static uint32_t xcursor_file_best_size(struct xcursor_file_header *fileHeader, @@ -728,8 +732,17 @@ xcursor_next_path(const char *path) return colon + 1; } -#define xcursor_white(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') -#define xcursor_sep(c) ((c) == ';' || (c) == ',') +static bool +xcursor_white(char c) +{ + return c == ' ' || c == '\t' || c == '\n'; +} + +static bool +xcursor_sep(char c) +{ + return c == ';' || c == ','; +} static char * xcursor_theme_inherits(const char *full) From 245d30ecb8a5001ec698e2db1fd77c3661563da5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:53:24 +0200 Subject: [PATCH 0841/1152] cursor: refactor xcursor_theme_inherits Use early returns and breaks to avoid dealing with very long indentation lines. Signed-off-by: Simon Ser --- cursor/xcursor.c | 62 ++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 0a7dfecb..5aab4ef4 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -755,39 +755,43 @@ xcursor_theme_inherits(const char *full) return NULL; f = fopen(full, "r"); - if (f) { - while (fgets(line, sizeof(line), f)) { - if (!strncmp(line, "Inherits", 8)) { - char *l = line + 8; - char *r; - while (*l == ' ') - l++; - if (*l != '=') - continue; + if (!f) + return NULL; + + while (fgets(line, sizeof(line), f)) { + if (strncmp(line, "Inherits", 8)) + continue; + + char *l = line + 8; + char *r; + while (*l == ' ') + l++; + if (*l != '=') + continue; + l++; + while (*l == ' ') + l++; + result = malloc(strlen(l) + 1); + if (!result) + break; + + r = result; + while (*l) { + while (xcursor_sep(*l) || xcursor_white(*l)) l++; - while (*l == ' ') - l++; - result = malloc(strlen(l) + 1); - if (result) { - r = result; - while (*l) { - while (xcursor_sep(*l) || xcursor_white(*l)) - l++; - if (!*l) - break; - if (r != result) - *r++ = ':'; - while (*l && !xcursor_white(*l) && - !xcursor_sep(*l)) - *r++ = *l++; - } - *r++ = '\0'; - } + if (!*l) break; - } + if (r != result) + *r++ = ':'; + while (*l && !xcursor_white(*l) && !xcursor_sep(*l)) + *r++ = *l++; } - fclose(f); + *r++ = '\0'; + + break; } + + fclose(f); return result; } From cf9065dfb8823d663e7e1e0b8f830d370381eff3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 11:57:31 +0200 Subject: [PATCH 0842/1152] cursor: drop xcursor_file abstraction Just use FILE * directly instead. Signed-off-by: Simon Ser --- cursor/xcursor.c | 60 ++++++++---------------------------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 5aab4ef4..307fb363 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -162,13 +162,6 @@ struct xcursor_comment { #define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) #define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ -struct xcursor_file { - void *closure; - int (*read)(struct xcursor_file *file, unsigned char *buf, int len); - int (*write)(struct xcursor_file *file, unsigned char *buf, int len); - int (*seek)(struct xcursor_file *file, long offset, int whence); -}; - struct xcursor_comments { int ncomment; /* number of comments */ struct xcursor_comments **comments; /* array of XcursorComment pointers */ @@ -255,14 +248,14 @@ xcursor_images_set_name(struct xcursor_images *images, const char *name) } static bool -xcursor_read_uint(struct xcursor_file *file, uint32_t *u) +xcursor_read_uint(FILE *file, uint32_t *u) { unsigned char bytes[4]; if (!file || !u) return false; - if ((*file->read)(file, bytes, 4) != 4) + if (fread(bytes, 1, 4, file) != 4) return false; *u = ((uint32_t)(bytes[0]) << 0) | @@ -298,7 +291,7 @@ xcursor_file_header_create(uint32_t ntoc) } static struct xcursor_file_header * -xcursor_read_file_header(struct xcursor_file *file) +xcursor_read_file_header(FILE *file) { struct xcursor_file_header head, *fileHeader; uint32_t skip; @@ -319,7 +312,7 @@ xcursor_read_file_header(struct xcursor_file *file) return NULL; skip = head.header - XCURSOR_FILE_HEADER_LEN; if (skip) - if ((*file->seek)(file, skip, SEEK_CUR) == EOF) + if (fseek(file, skip, SEEK_CUR) == EOF) return NULL; fileHeader = xcursor_file_header_create(head.ntoc); if (!fileHeader) @@ -344,18 +337,18 @@ xcursor_read_file_header(struct xcursor_file *file) } static bool -xcursor_seek_to_toc(struct xcursor_file *file, +xcursor_seek_to_toc(FILE *file, struct xcursor_file_header *fileHeader, int toc) { if (!file || !fileHeader || - (*file->seek)(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) + fseek(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) return false; return true; } static bool -xcursor_file_read_chunk_header(struct xcursor_file *file, +xcursor_file_read_chunk_header(FILE *file, struct xcursor_file_header *fileHeader, int toc, struct xcursor_chunk_header *chunkHeader) @@ -438,7 +431,7 @@ xcursor_find_image_toc(struct xcursor_file_header *fileHeader, } static struct xcursor_image * -xcursor_read_image(struct xcursor_file *file, +xcursor_read_image(FILE *file, struct xcursor_file_header *fileHeader, int toc) { @@ -495,7 +488,7 @@ xcursor_read_image(struct xcursor_file *file, } static struct xcursor_images * -xcursor_xc_file_load_images(struct xcursor_file *file, int size) +xcursor_xc_file_load_images(FILE *file, int size) { struct xcursor_file_header *fileHeader; uint32_t bestSize; @@ -537,46 +530,13 @@ xcursor_xc_file_load_images(struct xcursor_file *file, int size) return images; } -static int -xcursor_stdio_file_read(struct xcursor_file *file, unsigned char *buf, int len) -{ - FILE *f = file->closure; - return fread(buf, 1, len, f); -} - -static int -xcursor_stdio_file_write(struct xcursor_file *file, unsigned char *buf, int len) -{ - FILE *f = file->closure; - return fwrite(buf, 1, len, f); -} - -static int -xcursor_stdio_file_seek(struct xcursor_file *file, long offset, int whence) -{ - FILE *f = file->closure; - return fseek(f, offset, whence); -} - -static void -xcursor_stdio_file_initialize(FILE *stdfile, struct xcursor_file *file) -{ - file->closure = stdfile; - file->read = xcursor_stdio_file_read; - file->write = xcursor_stdio_file_write; - file->seek = xcursor_stdio_file_seek; -} - static struct xcursor_images * xcursor_file_load_images(FILE *file, int size) { - struct xcursor_file f; - if (!file) return NULL; - xcursor_stdio_file_initialize(file, &f); - return xcursor_xc_file_load_images(&f, size); + return xcursor_xc_file_load_images(file, size); } /* From 93b61fde1f4fae57222b176a789d993454cb6e91 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Apr 2022 12:01:19 +0200 Subject: [PATCH 0843/1152] cursor: rename local variables to snake case Signed-off-by: Simon Ser --- cursor/xcursor.c | 150 +++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 307fb363..19b56c0b 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -266,34 +266,34 @@ xcursor_read_uint(FILE *file, uint32_t *u) } static void -xcursor_file_header_destroy(struct xcursor_file_header *fileHeader) +xcursor_file_header_destroy(struct xcursor_file_header *file_header) { - free(fileHeader); + free(file_header); } static struct xcursor_file_header * xcursor_file_header_create(uint32_t ntoc) { - struct xcursor_file_header *fileHeader; + struct xcursor_file_header *file_header; if (ntoc > 0x10000) return NULL; - fileHeader = malloc(sizeof(struct xcursor_file_header) + + file_header = malloc(sizeof(struct xcursor_file_header) + ntoc * sizeof(struct xcursor_file_toc)); - if (!fileHeader) + if (!file_header) return NULL; - fileHeader->magic = XCURSOR_MAGIC; - fileHeader->header = XCURSOR_FILE_HEADER_LEN; - fileHeader->version = XCURSOR_FILE_VERSION; - fileHeader->ntoc = ntoc; - fileHeader->tocs = (struct xcursor_file_toc *) (fileHeader + 1); - return fileHeader; + file_header->magic = XCURSOR_MAGIC; + file_header->header = XCURSOR_FILE_HEADER_LEN; + file_header->version = XCURSOR_FILE_VERSION; + file_header->ntoc = ntoc; + file_header->tocs = (struct xcursor_file_toc *) (file_header + 1); + return file_header; } static struct xcursor_file_header * xcursor_read_file_header(FILE *file) { - struct xcursor_file_header head, *fileHeader; + struct xcursor_file_header head, *file_header; uint32_t skip; unsigned int n; @@ -314,60 +314,60 @@ xcursor_read_file_header(FILE *file) if (skip) if (fseek(file, skip, SEEK_CUR) == EOF) return NULL; - fileHeader = xcursor_file_header_create(head.ntoc); - if (!fileHeader) + file_header = xcursor_file_header_create(head.ntoc); + if (!file_header) return NULL; - fileHeader->magic = head.magic; - fileHeader->header = head.header; - fileHeader->version = head.version; - fileHeader->ntoc = head.ntoc; - for (n = 0; n < fileHeader->ntoc; n++) { - if (!xcursor_read_uint(file, &fileHeader->tocs[n].type)) + file_header->magic = head.magic; + file_header->header = head.header; + file_header->version = head.version; + file_header->ntoc = head.ntoc; + for (n = 0; n < file_header->ntoc; n++) { + if (!xcursor_read_uint(file, &file_header->tocs[n].type)) break; - if (!xcursor_read_uint(file, &fileHeader->tocs[n].subtype)) + if (!xcursor_read_uint(file, &file_header->tocs[n].subtype)) break; - if (!xcursor_read_uint(file, &fileHeader->tocs[n].position)) + if (!xcursor_read_uint(file, &file_header->tocs[n].position)) break; } - if (n != fileHeader->ntoc) { - xcursor_file_header_destroy(fileHeader); + if (n != file_header->ntoc) { + xcursor_file_header_destroy(file_header); return NULL; } - return fileHeader; + return file_header; } static bool xcursor_seek_to_toc(FILE *file, - struct xcursor_file_header *fileHeader, + struct xcursor_file_header *file_header, int toc) { - if (!file || !fileHeader || - fseek(file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) + if (!file || !file_header || + fseek(file, file_header->tocs[toc].position, SEEK_SET) == EOF) return false; return true; } static bool xcursor_file_read_chunk_header(FILE *file, - struct xcursor_file_header *fileHeader, + struct xcursor_file_header *file_header, int toc, - struct xcursor_chunk_header *chunkHeader) + struct xcursor_chunk_header *chunk_header) { - if (!file || !fileHeader || !chunkHeader) + if (!file || !file_header || !chunk_header) return false; - if (!xcursor_seek_to_toc(file, fileHeader, toc)) + if (!xcursor_seek_to_toc(file, file_header, toc)) return false; - if (!xcursor_read_uint(file, &chunkHeader->header)) + if (!xcursor_read_uint(file, &chunk_header->header)) return false; - if (!xcursor_read_uint(file, &chunkHeader->type)) + if (!xcursor_read_uint(file, &chunk_header->type)) return false; - if (!xcursor_read_uint(file, &chunkHeader->subtype)) + if (!xcursor_read_uint(file, &chunk_header->subtype)) return false; - if (!xcursor_read_uint(file, &chunkHeader->version)) + if (!xcursor_read_uint(file, &chunk_header->version)) return false; /* sanity check */ - if (chunkHeader->type != fileHeader->tocs[toc].type || - chunkHeader->subtype != fileHeader->tocs[toc].subtype) + if (chunk_header->type != file_header->tocs[toc].type || + chunk_header->subtype != file_header->tocs[toc].subtype) return false; return true; } @@ -379,72 +379,72 @@ dist(uint32_t a, uint32_t b) } static uint32_t -xcursor_file_best_size(struct xcursor_file_header *fileHeader, +xcursor_file_best_size(struct xcursor_file_header *file_header, uint32_t size, int *nsizesp) { unsigned int n; int nsizes = 0; - uint32_t bestSize = 0; - uint32_t thisSize; + uint32_t best_size = 0; + uint32_t this_size; - if (!fileHeader || !nsizesp) + if (!file_header || !nsizesp) return 0; - for (n = 0; n < fileHeader->ntoc; n++) { - if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) + for (n = 0; n < file_header->ntoc; n++) { + if (file_header->tocs[n].type != XCURSOR_IMAGE_TYPE) continue; - thisSize = fileHeader->tocs[n].subtype; - if (!bestSize || dist(thisSize, size) < dist(bestSize, size)) { - bestSize = thisSize; + this_size = file_header->tocs[n].subtype; + if (!best_size || dist(this_size, size) < dist(best_size, size)) { + best_size = this_size; nsizes = 1; - } else if (thisSize == bestSize) { + } else if (this_size == best_size) { nsizes++; } } *nsizesp = nsizes; - return bestSize; + return best_size; } static int -xcursor_find_image_toc(struct xcursor_file_header *fileHeader, +xcursor_find_image_toc(struct xcursor_file_header *file_header, uint32_t size, int count) { unsigned int toc; - uint32_t thisSize; + uint32_t this_size; - if (!fileHeader) + if (!file_header) return 0; - for (toc = 0; toc < fileHeader->ntoc; toc++) { - if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) + for (toc = 0; toc < file_header->ntoc; toc++) { + if (file_header->tocs[toc].type != XCURSOR_IMAGE_TYPE) continue; - thisSize = fileHeader->tocs[toc].subtype; - if (thisSize != size) + this_size = file_header->tocs[toc].subtype; + if (this_size != size) continue; if (!count) break; count--; } - if (toc == fileHeader->ntoc) + if (toc == file_header->ntoc) return -1; return toc; } static struct xcursor_image * xcursor_read_image(FILE *file, - struct xcursor_file_header *fileHeader, + struct xcursor_file_header *file_header, int toc) { - struct xcursor_chunk_header chunkHeader; + struct xcursor_chunk_header chunk_header; struct xcursor_image head; struct xcursor_image *image; int n; uint32_t *p; - if (!file || !fileHeader) + if (!file || !file_header) return NULL; - if (!xcursor_file_read_chunk_header(file, fileHeader, toc, &chunkHeader)) + if (!xcursor_file_read_chunk_header(file, file_header, toc, &chunk_header)) return NULL; if (!xcursor_read_uint(file, &head.width)) return NULL; @@ -469,9 +469,9 @@ xcursor_read_image(FILE *file, image = xcursor_image_create(head.width, head.height); if (image == NULL) return NULL; - if (chunkHeader.version < image->version) - image->version = chunkHeader.version; - image->size = chunkHeader.subtype; + if (chunk_header.version < image->version) + image->version = chunk_header.version; + image->size = chunk_header.subtype; image->xhot = head.xhot; image->yhot = head.yhot; image->delay = head.delay; @@ -490,8 +490,8 @@ xcursor_read_image(FILE *file, static struct xcursor_images * xcursor_xc_file_load_images(FILE *file, int size) { - struct xcursor_file_header *fileHeader; - uint32_t bestSize; + struct xcursor_file_header *file_header; + uint32_t best_size; int nsize; struct xcursor_images *images; int n; @@ -499,30 +499,30 @@ xcursor_xc_file_load_images(FILE *file, int size) if (!file || size < 0) return NULL; - fileHeader = xcursor_read_file_header(file); - if (!fileHeader) + file_header = xcursor_read_file_header(file); + if (!file_header) return NULL; - bestSize = xcursor_file_best_size(fileHeader, (uint32_t) size, &nsize); - if (!bestSize) { - xcursor_file_header_destroy(fileHeader); + best_size = xcursor_file_best_size(file_header, (uint32_t) size, &nsize); + if (!best_size) { + xcursor_file_header_destroy(file_header); return NULL; } images = xcursor_images_create(nsize); if (!images) { - xcursor_file_header_destroy(fileHeader); + xcursor_file_header_destroy(file_header); return NULL; } for (n = 0; n < nsize; n++) { - toc = xcursor_find_image_toc(fileHeader, bestSize, n); + toc = xcursor_find_image_toc(file_header, best_size, n); if (toc < 0) break; - images->images[images->nimage] = xcursor_read_image(file, fileHeader, + images->images[images->nimage] = xcursor_read_image(file, file_header, toc); if (!images->images[images->nimage]) break; images->nimage++; } - xcursor_file_header_destroy(fileHeader); + xcursor_file_header_destroy(file_header); if (images->nimage != nsize) { xcursor_images_destroy(images); images = NULL; From 5e4253ed50cfc9a132b5231f68a7084e0c3dc417 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 May 2022 12:18:16 +0200 Subject: [PATCH 0844/1152] util: fix code block language in docs Without {.xml}, Doxygen interprets the code as C. See [1] for details. [1]: https://www.doxygen.nl/manual/commands.html#cmdcode Signed-off-by: Simon Ser --- src/wayland-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 79977783..18c512e1 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -182,7 +182,7 @@ struct wl_message { * For example, consider a protocol interface `foo`, marked as version `1`, with * two requests and one event. * - * \code + * \code{.xml} * * * From 24244f26bfb39f7aef7606b503172bcb122b6477 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 4 Apr 2022 09:34:33 -0400 Subject: [PATCH 0845/1152] Meson: Override wayland-scanner if it can be run This allows projects to use Wayland as a Meson subproject and get the wayland-scanner executable when doing find_program('wayland-scanner'). Signed-off-by: Xavier Claessens --- src/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/meson.build b/src/meson.build index a601724b..a8a1d2ba 100644 --- a/src/meson.build +++ b/src/meson.build @@ -71,6 +71,10 @@ if get_option('scanner') ], filebase: 'wayland-scanner' ) + + if meson.can_run_host_binaries() + meson.override_find_program('wayland-scanner', wayland_scanner) + endif endif if meson.is_cross_build() or not get_option('scanner') From 73d4d2410e2e0d0579bacc7f87d37bf4ec15cbbb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 May 2022 20:15:35 +0200 Subject: [PATCH 0846/1152] build: bump to version 1.20.91 for the alpha release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8e951b9f..56678122 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.20.90', + version: '1.20.91', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From c2a150f7c253c65d376821df900fbe42b89c7e94 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 16:01:42 +0200 Subject: [PATCH 0847/1152] cursor: remove xcursor_file_load_images wrapper It's just calling xcursor_xc_file_load_images. Signed-off-by: Simon Ser --- cursor/xcursor.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 19b56c0b..fe7fff7e 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -530,15 +530,6 @@ xcursor_xc_file_load_images(FILE *file, int size) return images; } -static struct xcursor_images * -xcursor_file_load_images(FILE *file, int size) -{ - if (!file) - return NULL; - - return xcursor_xc_file_load_images(file, size); -} - /* * From libXcursor/src/library.c */ @@ -786,7 +777,7 @@ load_all_cursors_from_dir(const char *path, int size, continue; } - images = xcursor_file_load_images(f, size); + images = xcursor_xc_file_load_images(f, size); if (images) { xcursor_images_set_name(images, ent->d_name); From 0b8793ab0c5a6324490fc7cd2c51832c3fcc7c03 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 16:03:16 +0200 Subject: [PATCH 0848/1152] cursor: remove unnecessary parentheses in load_all_cursors_from_dir Signed-off-by: Simon Ser --- cursor/xcursor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index fe7fff7e..1974802e 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -763,7 +763,8 @@ load_all_cursors_from_dir(const char *path, int size, for (ent = readdir(dir); ent; ent = readdir(dir)) { #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type != DT_UNKNOWN && - (ent->d_type != DT_REG && ent->d_type != DT_LNK)) + ent->d_type != DT_REG && + ent->d_type != DT_LNK) continue; #endif From 6cf5e8f9324095f2226ee666eee9090fbc6da287 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 16:54:49 +0200 Subject: [PATCH 0849/1152] cursor: use getline instead of fgets This avoids storing 8KiB on the stack, and removes the line length limit. Signed-off-by: Simon Ser --- cursor/xcursor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 1974802e..315fe00a 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -698,7 +698,8 @@ xcursor_sep(char c) static char * xcursor_theme_inherits(const char *full) { - char line[8192]; + char *line = NULL; + size_t line_size = 0; char *result = NULL; FILE *f; @@ -709,7 +710,7 @@ xcursor_theme_inherits(const char *full) if (!f) return NULL; - while (fgets(line, sizeof(line), f)) { + while (getline(&line, &line_size, f) >= 0) { if (strncmp(line, "Inherits", 8)) continue; @@ -743,6 +744,8 @@ xcursor_theme_inherits(const char *full) } fclose(f); + free(line); + return result; } From 6c49a8f7e508ad51a913f6205b9359dec8132296 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:07:08 +0200 Subject: [PATCH 0850/1152] cursor: drop xcursor_images_set_name We don't ever need to set the name multiple times for a single struct xcursor_images, so we can just set the field directly. Also replace the hand-rolled logic with strdup. Signed-off-by: Simon Ser --- cursor/xcursor.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 315fe00a..dcebaeee 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -229,24 +229,6 @@ xcursor_images_destroy(struct xcursor_images *images) free(images); } -static void -xcursor_images_set_name(struct xcursor_images *images, const char *name) -{ - char *new; - - if (!images || !name) - return; - - new = malloc(strlen(name) + 1); - - if (!new) - return; - - strcpy(new, name); - free(images->name); - images->name = new; -} - static bool xcursor_read_uint(FILE *file, uint32_t *u) { @@ -784,7 +766,7 @@ load_all_cursors_from_dir(const char *path, int size, images = xcursor_xc_file_load_images(f, size); if (images) { - xcursor_images_set_name(images, ent->d_name); + images->name = strdup(ent->d_name); load_callback(images, user_data); } From f33356742e7f89962db6d7f58c3c3c6f9667cd15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:09:48 +0200 Subject: [PATCH 0851/1152] cursor: remove unnecessary ifs in xcursor_load_theme load_all_cursors_from_dir and xcursor_theme_inherits already have the NULL checks we want. Signed-off-by: Simon Ser --- cursor/xcursor.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index dcebaeee..2caa2d67 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -818,19 +818,14 @@ xcursor_load_theme(const char *theme, int size, continue; full = xcursor_build_fullname(dir, "cursors", ""); - - if (full) { - load_all_cursors_from_dir(full, size, load_callback, - user_data); - free(full); - } + load_all_cursors_from_dir(full, size, load_callback, + user_data); + free(full); if (!inherits) { full = xcursor_build_fullname(dir, "", "index.theme"); - if (full) { - inherits = xcursor_theme_inherits(full); - free(full); - } + inherits = xcursor_theme_inherits(full); + free(full); } free(dir); From 7a399383fc6b4586368c1083062bd28e9e30d5fb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:14:24 +0200 Subject: [PATCH 0852/1152] cursor: simplify xcursor_library_path - Use early returns - De-duplicate XDG_DATA_HOME code-paths - Don't crash on allocation failure - Use size_t when appropriate - Fix indentation Signed-off-by: Simon Ser --- cursor/xcursor.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 2caa2d67..b923596d 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -539,24 +539,24 @@ xcursor_xc_file_load_images(FILE *file, int size) static char * xcursor_library_path(void) { - const char *env_var; - char *path = NULL; - int pathlen = 0; + const char *env_var, *suffix; + char *path; + size_t path_size; env_var = getenv("XCURSOR_PATH"); - if (env_var) { - path = strdup(env_var); - } else { - env_var = getenv("XDG_DATA_HOME"); - if (env_var) { - pathlen = strlen(env_var) + strlen(CURSORDIR ":" XCURSORPATH) + 1; - path = malloc(pathlen); - snprintf(path, pathlen, "%s%s", env_var, - CURSORDIR ":" XCURSORPATH); - } else { - path = strdup(XDG_DATA_HOME_FALLBACK CURSORDIR ":" XCURSORPATH); - } - } + if (env_var) + return strdup(env_var); + + env_var = getenv("XDG_DATA_HOME"); + if (!env_var) + env_var = XDG_DATA_HOME_FALLBACK; + + suffix = CURSORDIR ":" XCURSORPATH; + path_size = strlen(env_var) + strlen(suffix) + 1; + path = malloc(path_size); + if (!path) + return NULL; + snprintf(path, path_size, "%s%s", env_var, suffix); return path; } From 1cb728246ba04fd7f8c0557d74fa5ea18d1f07c6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:16:17 +0200 Subject: [PATCH 0853/1152] cursor: fix indentation of xcursor_load_theme declaration Signed-off-by: Simon Ser --- cursor/xcursor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index b923596d..792ac185 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -798,8 +798,8 @@ load_all_cursors_from_dir(const char *path, int size, */ void xcursor_load_theme(const char *theme, int size, - void (*load_callback)(struct xcursor_images *, void *), - void *user_data) + void (*load_callback)(struct xcursor_images *, void *), + void *user_data) { char *full, *dir; char *inherits = NULL; From ccca002691a94cb6f25c092a33a5d5112e2d627a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:17:42 +0200 Subject: [PATCH 0854/1152] cursor: drop unused XCursor comment declarations Signed-off-by: Simon Ser --- cursor/xcursor.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 792ac185..cb376524 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -113,34 +113,6 @@ struct xcursor_chunk_header { uint32_t version; /* version of this type */ }; -/* - * Here's a list of the known chunk types - */ - -/* - * Comments consist of a 4-byte length field followed by - * UTF-8 encoded text - * - * Comment: - * ChunkHeader header chunk header - * CARD32 length bytes in text - * LISTofCARD8 text UTF-8 encoded text - */ - -#define XCURSOR_COMMENT_TYPE 0xfffe0001 -#define XCURSOR_COMMENT_VERSION 1 -#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4)) -#define XCURSOR_COMMENT_COPYRIGHT 1 -#define XCURSOR_COMMENT_LICENSE 2 -#define XCURSOR_COMMENT_OTHER 3 -#define XCURSOR_COMMENT_MAX_LEN 0x100000 - -struct xcursor_comment { - uint32_t version; - uint32_t comment_type; - char *comment; -}; - /* * Each cursor image occupies a separate image chunk. * The length of the image header follows the chunk header @@ -162,11 +134,6 @@ struct xcursor_comment { #define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) #define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ -struct xcursor_comments { - int ncomment; /* number of comments */ - struct xcursor_comments **comments; /* array of XcursorComment pointers */ -}; - /* * From libXcursor/src/file.c */ From dfe820efcea45d46dc436e8fa64def9c69efbdfa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:49:10 +0200 Subject: [PATCH 0855/1152] cursor: drop xcursor_add_path_elt Just use snprintf instead. It doesn't really matter if we have some duplicate slashes in filenames. Signed-off-by: Simon Ser --- cursor/xcursor.c | 51 ++++++++++++------------------------------------ 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index cb376524..6aa1c456 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -527,38 +527,17 @@ xcursor_library_path(void) return path; } -static void -xcursor_add_path_elt(char *path, const char *elt, int len) -{ - int pathlen = strlen(path); - - /* append / if the path doesn't currently have one */ - if (path[0] == '\0' || path[pathlen - 1] != '/') { - strcat(path, "/"); - pathlen++; - } - if (len == -1) - len = strlen(elt); - /* strip leading slashes */ - while (len && elt[0] == '/') { - elt++; - len--; - } - strncpy(path + pathlen, elt, len); - path[pathlen + len] = '\0'; -} - static char * xcursor_build_theme_dir(const char *dir, const char *theme) { const char *colon; const char *tcolon; char *full; - char *home; + const char *home, *homesep; int dirlen; int homelen; int themelen; - int len; + size_t full_size; if (!dir || !theme) return NULL; @@ -575,13 +554,15 @@ xcursor_build_theme_dir(const char *dir, const char *theme) themelen = tcolon - theme; - home = NULL; + home = ""; homelen = 0; + homesep = ""; if (*dir == '~') { home = getenv("HOME"); if (!home) return NULL; homelen = strlen(home); + homesep = "/"; dir++; dirlen--; } @@ -590,17 +571,12 @@ xcursor_build_theme_dir(const char *dir, const char *theme) * add space for any needed directory separators, one per component, * and one for the trailing null */ - len = 1 + homelen + 1 + dirlen + 1 + themelen + 1; - - full = malloc(len); + full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1; + full = malloc(full_size); if (!full) return NULL; - full[0] = '\0'; - - if (home) - xcursor_add_path_elt(full, home, -1); - xcursor_add_path_elt(full, dir, dirlen); - xcursor_add_path_elt(full, theme, themelen); + snprintf(full, full_size, "%s%s%.*s/%.*s", home, homesep, + dirlen, dir, themelen, theme); return full; } @@ -608,17 +584,16 @@ static char * xcursor_build_fullname(const char *dir, const char *subdir, const char *file) { char *full; + size_t full_size; if (!dir || !subdir || !file) return NULL; - full = malloc(strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1); + full_size = strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1; + full = malloc(full_size); if (!full) return NULL; - full[0] = '\0'; - xcursor_add_path_elt(full, dir, -1); - xcursor_add_path_elt(full, subdir, -1); - xcursor_add_path_elt(full, file, -1); + snprintf(full, full_size, "%s/%s/%s", dir, subdir, file); return full; } From 355c8e885c559354590c1a94a9aadf7030642151 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 May 2022 17:52:35 +0200 Subject: [PATCH 0856/1152] cursor: move xcursor_theme_inherits declarations at the top Per code style, declarations need to be at the start of the block. And make l const while at it. Signed-off-by: Simon Ser --- cursor/xcursor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 6aa1c456..8107b7c5 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -635,11 +635,13 @@ xcursor_theme_inherits(const char *full) return NULL; while (getline(&line, &line_size, f) >= 0) { + const char *l; + char *r; + if (strncmp(line, "Inherits", 8)) continue; - char *l = line + 8; - char *r; + l = line + 8; while (*l == ' ') l++; if (*l != '=') From 0297c2c47ad7321444add0be6cb8bf68cf270aac Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 4 Jun 2022 22:56:36 +0200 Subject: [PATCH 0857/1152] cursor/os-compatibility: remove strcpy/strcat usage These functions don't perform bounds checking, so they are easy to misuse and complicate audits. Signed-off-by: Simon Ser --- cursor/os-compatibility.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 8d51e528..9c84d685 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #ifdef HAVE_MEMFD_CREATE @@ -118,6 +119,7 @@ os_create_anonymous_file(off_t size) static const char template[] = "/wayland-cursor-shared-XXXXXX"; const char *path; char *name; + size_t name_size; int fd; #ifdef HAVE_MEMFD_CREATE @@ -139,12 +141,12 @@ os_create_anonymous_file(off_t size) return -1; } - name = malloc(strlen(path) + sizeof(template)); + name_size = strlen(path) + sizeof(template); + name = malloc(name_size); if (!name) return -1; - strcpy(name, path); - strcat(name, template); + snprintf(name, name_size, "%s%s", path, template); fd = create_tmpfile_cloexec(name); From f710d01663bc054825b0ed84be20ab5fc201362e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 4 Jun 2022 22:58:50 +0200 Subject: [PATCH 0858/1152] cursor/os-compatibility: fix trailing space Signed-off-by: Simon Ser --- cursor/os-compatibility.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 9c84d685..207e4911 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -168,7 +168,7 @@ int os_resize_anonymous_file(int fd, off_t size) { #ifdef HAVE_POSIX_FALLOCATE - /* + /* * Filesystems that do support fallocate will return EINVAL or * EOPNOTSUPP. In this case we need to fall back to ftruncate */ From 9434e8d69f76d7859ed7b18edc5a62450ad8d040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Fri, 11 Mar 2022 14:08:49 +0100 Subject: [PATCH 0859/1152] Check that XDG base directories paths are absolute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The [spec][1] reads: > All paths set in these environment variables must be absolute. If an > implementation encounters a relative path in any of these variables it should > consider the path invalid and ignore it. and > If $XDG_DATA_HOME is either not set or empty, a default equal to > $HOME/.local/share should be used. Testing that the path is absolute also entails that is is non-empty. [1]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html Signed-off-by: Antonin Décimo --- cursor/os-compatibility.c | 2 +- cursor/xcursor.c | 2 +- src/wayland-client.c | 4 ++-- src/wayland-server.c | 7 ++++--- tests/compositor-introspection-test.c | 2 +- tests/protocol-logger-test.c | 2 +- tests/socket-test.c | 2 +- tests/test-runner.c | 4 ++-- 8 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 207e4911..07452a57 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -136,7 +136,7 @@ os_create_anonymous_file(off_t size) #endif { path = getenv("XDG_RUNTIME_DIR"); - if (!path) { + if (!path || path[0] != '/') { errno = ENOENT; return -1; } diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 8107b7c5..43a5292c 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -515,7 +515,7 @@ xcursor_library_path(void) return strdup(env_var); env_var = getenv("XDG_DATA_HOME"); - if (!env_var) + if (!env_var || env_var[0] != '/') env_var = XDG_DATA_HOME_FALLBACK; suffix = CURSORDIR ":" XCURSORPATH; diff --git a/src/wayland-client.c b/src/wayland-client.c index 75692e6e..659c1325 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1076,8 +1076,8 @@ connect_to_socket(const char *name) path_is_absolute = name[0] == '/'; runtime_dir = getenv("XDG_RUNTIME_DIR"); - if (!runtime_dir && !path_is_absolute) { - wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n"); + if (((!runtime_dir || runtime_dir[0] != '/') && !path_is_absolute)) { + wl_log("error: XDG_RUNTIME_DIR is invalid or not set in the environment.\n"); /* to prevent programs reporting * "failed to create display: Success" */ errno = ENOENT; diff --git a/src/wayland-server.c b/src/wayland-server.c index 93e42c7a..00cfc27a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1557,8 +1557,9 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name) if (name[0] != '/') { runtime_dir = getenv("XDG_RUNTIME_DIR"); - if (!runtime_dir) { - wl_log("error: XDG_RUNTIME_DIR not set in the environment\n"); + if (!runtime_dir || runtime_dir[0] != '/') { + wl_log("error: XDG_RUNTIME_DIR is invalid or not set in" + " the environment\n"); /* to prevent programs reporting * "failed to add socket: Success" */ @@ -1718,7 +1719,7 @@ wl_display_add_socket_fd(struct wl_display *display, int sock_fd) * * If the socket name is a relative path, the Unix socket will be created in * the directory pointed to by environment variable XDG_RUNTIME_DIR. If - * XDG_RUNTIME_DIR is not set, then this function fails and returns -1. + * XDG_RUNTIME_DIR is invalid or not set, then this function fails and returns -1. * * If the socket name is an absolute path, then it is used as-is for the * the Unix socket. diff --git a/tests/compositor-introspection-test.c b/tests/compositor-introspection-test.c index 83194ce2..064d2530 100644 --- a/tests/compositor-introspection-test.c +++ b/tests/compositor-introspection-test.c @@ -40,7 +40,7 @@ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); - assert(val && "set $XDG_RUNTIME_DIR to run this test"); + assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c index 80c74aae..a0ebd22a 100644 --- a/tests/protocol-logger-test.c +++ b/tests/protocol-logger-test.c @@ -40,7 +40,7 @@ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); - assert(val && "set $XDG_RUNTIME_DIR to run this test"); + assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } diff --git a/tests/socket-test.c b/tests/socket-test.c index 8d39edce..78743dc3 100644 --- a/tests/socket-test.c +++ b/tests/socket-test.c @@ -51,7 +51,7 @@ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); - assert(val && "set $XDG_RUNTIME_DIR to run this test"); + assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } diff --git a/tests/test-runner.c b/tests/test-runner.c index c0247b57..d07dab15 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -180,7 +180,7 @@ set_xdg_runtime_dir(void) xrd_env = getenv("XDG_RUNTIME_DIR"); /* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */ assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests-XXXXXX", - xrd_env ? xrd_env : "/tmp") < PATH_MAX) + (xrd_env && xrd_env[0] == '/') ? xrd_env : "/tmp") < PATH_MAX) && "test error: XDG_RUNTIME_DIR too long"); assert(mkdtemp(xdg_runtime_dir) && "test error: mkdtemp failed"); @@ -200,7 +200,7 @@ static void rmdir_xdg_runtime_dir(void) { const char *xrd_env = getenv("XDG_RUNTIME_DIR"); - assert(xrd_env && "No XDG_RUNTIME_DIR set"); + assert(xrd_env && xrd_env[0] == '/' && "No XDG_RUNTIME_DIR set"); /* rmdir may fail if some test didn't do clean up */ if (rmdir(xrd_env) == -1) From a8246a9f0f60d83755be14e7fec2b0683a09f647 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Thu, 26 May 2022 12:05:15 +0300 Subject: [PATCH 0860/1152] client: Document best practices for event queue changes Document the proper way to deal with event queue changes, in order to guarantee proper handing of all events which were queued before the queue change takes effect, especially in multi-threaded setups. Make a special note about queue changes of newly created proxies, which require the use of a proxy wrapper for thread safety. Signed-off-by: Alexandros Frantzis Suggested-by: Pekka Paalanen --- src/wayland-client.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 659c1325..3e42f702 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2311,6 +2311,19 @@ wl_proxy_get_class(struct wl_proxy *proxy) * queued in \c queue from now. If queue is NULL, then the display's * default queue is set to the proxy. * + * In order to guarantee proper handing of all events which were queued + * before the queue change takes effect, it is required to dispatch the + * proxy's old event queue after setting a new event queue. + * + * This is particularly important for multi-threaded setups, where it is + * possible for events to be queued to the proxy's old queue from a + * different thread during the invocation of this function. + * + * To ensure that all events for a newly created proxy are dispatched + * on a particular queue, it is necessary to use a proxy wrapper if + * events are read and dispatched on more than one thread. See + * wl_proxy_create_wrapper() for more details. + * * \note By default, the queue set in proxy is the one inherited from parent. * * \sa wl_display_dispatch_queue() From 444d0ff3381a8b2f89a9e84a6ca9b8622fe97170 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Thu, 26 May 2022 12:18:28 +0300 Subject: [PATCH 0861/1152] client: Lock display when setting a proxy event queue Assignments to a wl_proxy's queue member are currently not synchronized with potential reads of that member during event reading/queuing. Assuming atomic pointer value reads and writes (which is a reasonable assumption), and using the documented best practices to handle event queue changes, a queue change should still be safe to perform. That being said, such implicitly atomic accesses are difficult to assess for correctness, especially since they do not introduce memory barriers. To make the code more obviously correct, and handle any potential races we are not currently aware of, this commit updates wl_proxy_set_queue() to set the proxy's event queue under the display lock (all other proxy queue accesses are already done under the display lock). Signed-off-by: Alexandros Frantzis Suggested-by: Pekka Paalanen --- src/wayland-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 3e42f702..90fb9c7d 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2333,12 +2333,16 @@ wl_proxy_get_class(struct wl_proxy *proxy) WL_EXPORT void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) { + pthread_mutex_lock(&proxy->display->mutex); + if (queue) { assert(proxy->display == queue->display); proxy->queue = queue; } else { proxy->queue = &proxy->display->default_queue; } + + pthread_mutex_unlock(&proxy->display->mutex); } /** Create a proxy wrapper for making queue assignments thread-safe From 07c8f4157694b4eb89ce220bcd1456320815c118 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Jun 2022 20:52:32 +0200 Subject: [PATCH 0862/1152] build: bump to version 1.20.92 for the beta release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 56678122..2d496ba4 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.20.91', + version: '1.20.92', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From dd00220b1ef6a4c823632a02b535b40602bfb8d4 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Mon, 30 May 2022 09:14:04 +0200 Subject: [PATCH 0863/1152] cursor/os-compatibility: handle EINTR gracefully If os_resize_anonymous_file() called from os_create_anonymous_file() fails with EINTR (Interrupted system call), then the buffer allocation fails. To avoid that, retry posix_fallocate() on EINTR. However, in the presence of an alarm, the interrupt may trigger repeatedly and prevent a large posix_fallocate() to ever complete successfully, so we need to first block SIGALRM to prevent this. Signed-off-by: Olivier Fourdan --- cursor/os-compatibility.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 07452a57..f2445ced 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -168,11 +169,28 @@ int os_resize_anonymous_file(int fd, off_t size) { #ifdef HAVE_POSIX_FALLOCATE + sigset_t mask; + sigset_t old_mask; + /* - * Filesystems that do support fallocate will return EINVAL or + * posix_fallocate() might be interrupted, so we need to check + * for EINTR and retry in that case. + * However, in the presence of an alarm, the interrupt may trigger + * repeatedly and prevent a large posix_fallocate() to ever complete + * successfully, so we need to first block SIGALRM to prevent + * this. + */ + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + sigprocmask(SIG_BLOCK, &mask, &old_mask); + /* + * Filesystems that do not support fallocate will return EINVAL or * EOPNOTSUPP. In this case we need to fall back to ftruncate */ - errno = posix_fallocate(fd, 0, size); + do { + errno = posix_fallocate(fd, 0, size); + } while (errno == EINTR); + sigprocmask(SIG_SETMASK, &old_mask, NULL); if (errno == 0) return 0; else if (errno != EINVAL && errno != EOPNOTSUPP) From 1b00df864c6816905628a8eae49c24d2aed287af Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 12 May 2022 19:29:11 +0200 Subject: [PATCH 0864/1152] server: check visibility before sending global/global_remove See the previous discussion at [1]: libwayland incorrectly skips the visibility checks when sending global/global_remove events. The check is only performed when a client performs a wl_display.get_registry request. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/148 Signed-off-by: Simon Ser --- src/wayland-server.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 00cfc27a..732f153e 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1252,11 +1252,12 @@ wl_global_create(struct wl_display *display, wl_list_insert(display->global_list.prev, &global->link); wl_list_for_each(resource, &display->registry_resource_list, link) - wl_resource_post_event(resource, - WL_REGISTRY_GLOBAL, - global->name, - global->interface->name, - global->version); + if (wl_global_is_visible(resource->client, global)) + wl_resource_post_event(resource, + WL_REGISTRY_GLOBAL, + global->name, + global->interface->name, + global->version); return global; } @@ -1294,8 +1295,9 @@ wl_global_remove(struct wl_global *global) global->name); wl_list_for_each(resource, &display->registry_resource_list, link) - wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, - global->name); + if (wl_global_is_visible(resource->client, global)) + wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, + global->name); global->removed = true; } From 2fb4cdebbedb2c0468ce331cadafd0dfc83fb08f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 12 May 2022 19:30:38 +0200 Subject: [PATCH 0865/1152] tests: add a test for dynamic filtered globals Ensure dynamically created and destroyed globals which are filtered don't trigger any global/global_remove event. Signed-off-by: Simon Ser --- tests/display-test.c | 61 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/tests/display-test.c b/tests/display-test.c index a6f410da..bcb3267f 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1006,9 +1006,16 @@ registry_handle_filtered(void *data, struct wl_registry *registry, } } +static void +registry_handle_remove_filtered(void *data, struct wl_registry *registry, + uint32_t id) +{ + assert(false); +} + static const struct wl_registry_listener registry_listener_filtered = { registry_handle_filtered, - NULL + registry_handle_remove_filtered, }; static void @@ -1044,6 +1051,58 @@ TEST(filtered_global_is_hidden) display_destroy(d); } +static void +get_dynamic_globals(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, ®istry_listener_filtered, data); + wl_display_roundtrip(c->wl_display); + + /* Wait for the server to create a new global */ + assert(stop_display(c, 1) >= 0); + + /* Check that we don't see it */ + wl_display_roundtrip(c->wl_display); + + /* Wait for the server to remove that global */ + assert(stop_display(c, 1) >= 0); + + /* Check that we don't get a global_remove event */ + wl_display_roundtrip(c->wl_display); + + wl_registry_destroy(registry); + client_disconnect_nocheck(c); +} + +TEST(filtered_dynamic_global_is_hidden) +{ + struct display *d; + struct wl_global *g; + + d = display_create(); + wl_display_set_global_filter(d->wl_display, global_filter, NULL); + + /* Create a client and let it enumerate the globals */ + client_create_noarg(d, get_dynamic_globals); + display_run(d); + + /* Dynamically create a new global */ + g = wl_global_create(d->wl_display, &wl_data_offer_interface, + 1, d, bind_data_offer); + + display_resume(d); + + /* Dynamically remove the global */ + wl_global_destroy(g); + + display_resume(d); + + display_destroy(d); +} + static void check_bind_error(struct client *c) { From 7eb00b070d8a7ec98f58980862b63a0063c66d6b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 31 May 2022 19:23:38 +0200 Subject: [PATCH 0866/1152] server: add PID race condition disclaimer to wl_client_get_credentials PIDs are re-used and cannot be used to reliably check the identity of a Wayland client. Signed-off-by: Simon Ser --- src/wayland-server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 732f153e..4bcc9aeb 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -578,6 +578,9 @@ err_client: * SO_PEERCRED, on the client socket fd. All the pointers can be * NULL, if the caller is not interested in a particular ID. * + * Note, process IDs are subject to race conditions and are not a reliable way + * to identify a client. + * * Be aware that for clients that a compositor forks and execs and * then connects using socketpair(), this function will return the * credentials for the compositor. The credentials for the socketpair From 41b10c74589c5350931a688b0e828c85652dae45 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 15 Jun 2022 10:37:18 +0200 Subject: [PATCH 0867/1152] server: warn about global filtering consistency The filtering needs to be static given a client and a global, otherwise libwayland will misbehave. Signed-off-by: Simon Ser References: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/241#note_1421888 --- src/wayland-server.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 4bcc9aeb..8e24b41b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1208,6 +1208,10 @@ wl_display_destroy(struct wl_display *display) * Setting the filter NULL will result in all globals being * advertised to all clients. The default is no filter. * + * The filter should be installed before any client connects and should always + * take the same decision given a client and a global. Not doing so will result + * in inconsistent filtering and broken wl_registry event sequences. + * * \memberof wl_display */ WL_EXPORT void From 8e322a5a99db1cefb7494f082a5525d2cba64174 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 Jun 2022 21:59:18 +0200 Subject: [PATCH 0868/1152] build: bump to version 1.20.93 for the RC1 release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 2d496ba4..5487dc9c 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.20.92', + version: '1.20.93', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From c7fc1e79ca50402acdd8627dcdf7dd0286924d99 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jun 2022 11:59:26 +0200 Subject: [PATCH 0869/1152] util: set errno when hitting WL_MAP_MAX_OBJECTS Callers may check errno when wl_map_insert_* functions return an error (since [1]). Make sure it's always set to a meaningful value when returning an error, otherwise callers might end up checking an errno coming from a completely different function. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/205 Signed-off-by: Simon Ser Fixes: b19488c7154b ("util: Limit size of wl_map") --- src/wayland-util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index 41f0986b..bb2a1838 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -232,6 +232,7 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) * better make it a NULL so wl_map_for_each doesn't * dereference it later. */ entry->data = NULL; + errno = ENOSPC; return 0; } entry->data = data; @@ -254,8 +255,10 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) i -= WL_SERVER_ID_START; } - if (i > WL_MAP_MAX_OBJECTS) + if (i > WL_MAP_MAX_OBJECTS) { + errno = ENOSPC; return -1; + } count = entries->size / sizeof *start; if (count < i) { @@ -299,8 +302,10 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i) i -= WL_SERVER_ID_START; } - if (i > WL_MAP_MAX_OBJECTS) + if (i > WL_MAP_MAX_OBJECTS) { + errno = ENOSPC; return -1; + } count = entries->size / sizeof *start; if (count < i) { From 68842b34039eb8efb6b7677cba5a0ddfceac34e0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 24 Jun 2022 13:45:58 +1000 Subject: [PATCH 0870/1152] protocol: minor clarification for axis_discrete events Explicitly spell out that multiple axis_discrete events *for the same axis* within the same wl_pointer.frame are not permitted. References: https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/911#note_1438099 Signed-off-by: Peter Hutterer --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 1da3db9d..10781cf1 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2231,7 +2231,8 @@ axis number within the same wl_pointer.frame. Note that the protocol allows for other events to occur between the axis_discrete and its coupled axis event, including other axis_discrete or axis - events. + events. A wl_pointer.frame must not contain more than one axis_discrete + event per axis type. This event is optional; continuous scrolling devices like two-finger scrolling on touchpads do not have discrete From 8135e856ebd79872f886466e9cee39affb7d9ee8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 30 Jun 2022 23:59:11 +0200 Subject: [PATCH 0871/1152] build: bump to version 1.21.0 for the official release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5487dc9c..8bb47c25 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.20.93', + version: '1.21.0', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From 4f6c6e7c0f27008b6c4e1f4da5c61b80af2f407b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 1 Jul 2022 00:11:50 +0200 Subject: [PATCH 0872/1152] build: re-open main branch for regular development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8bb47c25..f469756f 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.21.0', + version: '1.21.90', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From 7cdc20cee6cb967c1975896cb60bcc9d1221819a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 28 May 2022 10:07:12 +0200 Subject: [PATCH 0873/1152] Add release.sh Replace xorg-util-modular's release script with our own, tailored for Wayland only. Does the same thing but in 71 lines of code instead of 1k. Creates a GitLab release via glab instead of trying to upload to a web server via ssh. Signed-off-by: Simon Ser --- release.sh | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ releasing.txt | 24 +++--------------- 2 files changed, 74 insertions(+), 20 deletions(-) create mode 100755 release.sh diff --git a/release.sh b/release.sh new file mode 100755 index 00000000..59e6eb07 --- /dev/null +++ b/release.sh @@ -0,0 +1,70 @@ +#!/bin/sh -eu + +build_dir=build-release + +if ! type glab >/dev/null; then + echo "glab is needed to create a release" + exit 1 +fi + +case "$(git rev-parse --abbrev-ref HEAD)" in +main | [0-9]*.[0-9]*) + ;; +*) + echo "Not on the main or a stable branch" + exit 1 +esac + +if [ -n "$(git log @{upstream}..)" ]; then + echo "The main branch has unpushed commits" + exit 1 +fi + +meson_options="" +if [ -e "$build_dir" ]; then + meson_options="$meson_options --wipe" +fi +meson setup "$build_dir" $meson_options + +prev_version="$(git describe --tags --abbrev=0)" +version="$(meson introspect "$build_dir" --projectinfo | jq -r .version)" +if [ "$version" = "$prev_version" ]; then + echo "Version not bumped" + exit 1 +fi + +ninja -C "$build_dir" dist + +archive_name="wayland-$version.tar.xz" +archive_path="$build_dir/meson-dist/$archive_name" +gpg --detach-sig "$archive_path" + +sha256="$(cd $build_dir/meson-dist && sha256sum $archive_name)" +sha512="$(cd $build_dir/meson-dist && sha512sum $archive_name)" +archive_url="https://gitlab.freedesktop.org/wayland/wayland/-/releases/$version/downloads/$archive_name" +announce_path="$build_dir/meson-dist/wayland-$version-announce.eml" +cat >"$announce_path" < +Subject: [ANNOUNCE] wayland $version + +`git shortlog --no-merges "$prev_version.."` + +git tag: $version + +$archive_url +SHA256: $sha256 +SHA512: $sha512 +PGP: $archive_url.sig +EOF + +echo "Release announcement written to $announce_path" + +echo -n "Release wayland $version? [y/N] " +read answer +if [ "$answer" != "y" ]; then + exit 1 +fi + +git tag -s -m "$version" "$version" +git push --tags +glab release create "$version" "$archive_path"* --notes "" diff --git a/releasing.txt b/releasing.txt index db879715..e93f53dd 100644 --- a/releasing.txt +++ b/releasing.txt @@ -17,27 +17,11 @@ To make a release of Wayland, follow these steps. 2. Run the release.sh script to generate the tarballs, sign and upload them, and generate a release announcement template. - This script can be obtained from X.org's modular package: - http://cgit.freedesktop.org/xorg/util/modular/tree/release.sh - - The script supports a --dry-run option to test it without actually - doing a release. If the script fails on the distcheck step due to - a testsuite error that can't be fixed for some reason, you can - skip testsuite by specifying the --dist argument. Pass --help to - see other supported options. - - $ release.sh . - - For Wayland official and point releases, also publish the publican - documentation to wayland.freedesktop.org: - - $ ./publish-doc - - 3. Compose the release announcements. The script will generate - *.x.y.z.announce files with a list of changes and tags. Prepend - it with a human-readable listing of the most notable changes. - For x.y.0 releases, indicate the schedule for the x.y+1.0 + 3. Compose the release announcements. The script will generate a + wayland-x.y.z-announce.eml file with a list of changes and tags. + Prepend it with a human-readable listing of the most notable + changes. For x.y.0 releases, indicate the schedule for the x.y+1.0 release. 4. PGP sign the release announcements and send them to From 13b05c9ed1570765923a28b277ca385001c2b5c6 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 12 Jul 2022 09:12:33 -0700 Subject: [PATCH 0874/1152] Do not allow nullable arrays, which were not correctly implemented Nullable arrays, which are not used anywhere, were marshalled the same way as an empty non-null array. The demarshalling logic did not recognize anything as a null array. Given this, it seems better to just explicitly not support it. Fixes https://gitlab.freedesktop.org/wayland/wayland/-/issues/306. Signed-off-by: Ian Douglas Scott --- src/connection.c | 2 +- src/scanner.c | 3 +-- tests/connection-test.c | 10 ---------- tests/message-test.c | 6 ++---- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/connection.c b/src/connection.c index bf976762..594f2e93 100644 --- a/src/connection.c +++ b/src/connection.c @@ -636,7 +636,7 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, closure->args[i].n = object ? object->id : 0; break; case 'a': - if (!arg.nullable && args[i].a == NULL) + if (args[i].a == NULL) goto err_null; break; case 'h': diff --git a/src/scanner.c b/src/scanner.c index 6a956036..551d8177 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -411,11 +411,10 @@ static bool is_nullable_type(struct arg *arg) { switch (arg->type) { - /* Strings, objects, and arrays are possibly nullable */ + /* Strings and objects are possibly nullable */ case STRING: case OBJECT: case NEW_ID: - case ARRAY: return true; default: return false; diff --git a/tests/connection-test.c b/tests/connection-test.c index eea92873..592e27ef 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -305,7 +305,6 @@ TEST(connection_marshal_nullables) { struct marshal_data data; struct wl_object object; - struct wl_array array; const char text[] = "curry"; setup_marshal_data(&data); @@ -317,9 +316,6 @@ TEST(connection_marshal_nullables) marshal(&data, "?o", 12, NULL); assert(data.buffer[2] == 0); - marshal(&data, "?a", 12, NULL); - assert(data.buffer[2] == 0); - marshal(&data, "?s", 12, NULL); assert(data.buffer[2] == 0); @@ -327,12 +323,6 @@ TEST(connection_marshal_nullables) marshal(&data, "?o", 12, &object); assert(data.buffer[2] == object.id); - array.data = (void *) text; - array.size = sizeof text; - marshal(&data, "?a", 20, &array); - assert(data.buffer[2] == array.size); - assert(memcmp(&data.buffer[3], text, array.size) == 0); - marshal(&data, "?s", 20, text); assert(data.buffer[2] == sizeof text); assert(strcmp((char *) &data.buffer[3], text) == 0); diff --git a/tests/message-test.c b/tests/message-test.c index 4e693923..40293a99 100644 --- a/tests/message-test.c +++ b/tests/message-test.c @@ -64,8 +64,7 @@ TEST(message_count_arrays) { "multiple", "aaiufaasonhaa", NULL }, { "leading_version", "2aaiufaasonhaa", NULL }, { "among_nullables", "iufsa?oa?nah", NULL }, - { "nullable", "?aiufs?a?onh?a", NULL }, - { "all_mixed", "2?aiufas?oa?na", NULL }, + { "all_mixed", "2aiufas?oa?na", NULL }, }; const struct { const struct wl_message *message; @@ -81,8 +80,7 @@ TEST(message_count_arrays) { &fake_messages[5], 6 }, { &fake_messages[6], 6 }, { &fake_messages[7], 3 }, - { &fake_messages[8], 3 }, - { &fake_messages[9], 4 }, + { &fake_messages[8], 4 }, }; for (i = 0; i < ARRAY_LENGTH(messages); ++i) { From 971f8e4ace3d4080340f43574043c31f46db312f Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 14 Jul 2022 08:36:21 -0700 Subject: [PATCH 0875/1152] Do not allow nullable `new_id` The usefulness of this is limited, and `libwayland-client` doesn't provide a way to pass a null `new_id` since the id is generated by the library and given to the caller as the return value. Signed-off-by: Ian Douglas Scott --- src/connection.c | 4 ++-- src/scanner.c | 1 - tests/connection-test.c | 3 --- tests/message-test.c | 4 ++-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/connection.c b/src/connection.c index 594f2e93..ceaeac14 100644 --- a/src/connection.c +++ b/src/connection.c @@ -630,7 +630,7 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, break; case 'n': object = args[i].o; - if (!arg.nullable && object == NULL) + if (object == NULL) goto err_null; closure->args[i].n = object ? object->id : 0; @@ -799,7 +799,7 @@ wl_connection_demarshal(struct wl_connection *connection, id = *p++; closure->args[i].n = id; - if (id == 0 && !arg.nullable) { + if (id == 0) { wl_log("NULL new ID received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); diff --git a/src/scanner.c b/src/scanner.c index 551d8177..da8adea4 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -414,7 +414,6 @@ is_nullable_type(struct arg *arg) /* Strings and objects are possibly nullable */ case STRING: case OBJECT: - case NEW_ID: return true; default: return false; diff --git a/tests/connection-test.c b/tests/connection-test.c index 592e27ef..9762e0da 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -245,9 +245,6 @@ TEST(connection_marshal) marshal(&data, "n", 12, &object); assert(data.buffer[2] == object.id); - marshal(&data, "?n", 12, NULL); - assert(data.buffer[2] == 0); - array.data = (void *) text; array.size = sizeof text; marshal(&data, "a", 20, &array); diff --git a/tests/message-test.c b/tests/message-test.c index 40293a99..86f387ab 100644 --- a/tests/message-test.c +++ b/tests/message-test.c @@ -63,8 +63,8 @@ TEST(message_count_arrays) { "middle", "iufasonh", NULL }, { "multiple", "aaiufaasonhaa", NULL }, { "leading_version", "2aaiufaasonhaa", NULL }, - { "among_nullables", "iufsa?oa?nah", NULL }, - { "all_mixed", "2aiufas?oa?na", NULL }, + { "among_nullables", "iufsa?oa?sah", NULL }, + { "all_mixed", "2aiufas?oa?sa", NULL }, }; const struct { const struct wl_message *message; From 60827b862e4f0ef2b5117df30494a7f5918dd8b1 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 12 Jul 2022 21:23:55 -0700 Subject: [PATCH 0876/1152] Document which type are nullable, and wire format for null value Signed-off-by: Ian Douglas Scott --- doc/publican/sources/Protocol.xml | 5 +++-- src/wayland-util.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 580cecbc..57d88357 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -151,7 +151,8 @@ Starts with an unsigned 32-bit length (including null terminator), followed by the string contents, including terminating null byte, - then padding to a 32-bit boundary. + then padding to a 32-bit boundary. A null value is represented + with a length of 0. @@ -159,7 +160,7 @@ object - 32-bit object ID. + 32-bit object ID. A null value is represented with an ID of 0. diff --git a/src/wayland-util.h b/src/wayland-util.h index 18c512e1..4d59231f 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -118,7 +118,7 @@ struct wl_object; * * `n`: new_id * * `a`: array * * `h`: fd - * * `?`: following argument is nullable + * * `?`: following argument (`o` or `s`) is nullable * * While demarshaling primitive arguments is straightforward, when demarshaling * messages containing `object` or `new_id` arguments, the protocol From 73468bab7d12fd4d7b62d3b50a56e77acd977607 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 5 Aug 2022 00:35:40 +0200 Subject: [PATCH 0877/1152] server: Extend display name string size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typically this is a number between 0 and 32. Just that the compiler doesn't know that well. Make the string buffer a bit larger, so that it fits the longer integers. Fixes build warnings like: ../subprojects/wayland/src/wayland-server.c: In function ‘wl_display_add_socket_auto’: ../subprojects/wayland/src/wayland-server.c:1649:70: error: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 8 [-Werror=format-truncation=] 1649 | snprintf(display_name, sizeof display_name, "wayland-%d", displayno); | ^~ ../subprojects/wayland/src/wayland-server.c:1649:61: note: directive argument in the range [-2147483647, 32] 1649 | snprintf(display_name, sizeof display_name, "wayland-%d", displayno); | ^~~~~~~~~~~~ ../subprojects/wayland/src/wayland-server.c:1649:17: note: ‘snprintf’ output between 10 and 20 bytes into a destination of size 16 1649 | snprintf(display_name, sizeof display_name, "wayland-%d", displayno); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Seen in GTK CI. Signed-off-by: Carlos Garnacho --- src/wayland-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 8e24b41b..a44982fb 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1635,7 +1635,7 @@ wl_display_add_socket_auto(struct wl_display *display) { struct wl_socket *s; int displayno = 0; - char display_name[16] = ""; + char display_name[20] = ""; /* A reasonable number of maximum default sockets. If * you need more than this, use the explicit add_socket API. */ From 68fef9922edd9add56d97c5bb4d64b6a3179764b Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 6 Sep 2022 15:05:37 +0200 Subject: [PATCH 0878/1152] build: Make release.sh generic The "release.sh" script is a convenient and documented way to release Wayland packages. Unfortunately, the actual package name is hardcoded, meaning that to reuse that script in other Wayland projects, one needs to duplicate the script and amend it. Use meson to determine the actual project name, so that the same script can be invoked from any relevant Wayland project. Signed-off-by: Olivier Fourdan --- release.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/release.sh b/release.sh index 59e6eb07..697bf40a 100755 --- a/release.sh +++ b/release.sh @@ -33,19 +33,25 @@ if [ "$version" = "$prev_version" ]; then exit 1 fi +name="$(meson introspect "$build_dir" --projectinfo | jq -r .descriptive_name)" +if [ "$name" = "" ]; then + echo "Cannot determine project name" + exit 1 +fi + ninja -C "$build_dir" dist -archive_name="wayland-$version.tar.xz" +archive_name="$name-$version.tar.xz" archive_path="$build_dir/meson-dist/$archive_name" gpg --detach-sig "$archive_path" sha256="$(cd $build_dir/meson-dist && sha256sum $archive_name)" sha512="$(cd $build_dir/meson-dist && sha512sum $archive_name)" -archive_url="https://gitlab.freedesktop.org/wayland/wayland/-/releases/$version/downloads/$archive_name" -announce_path="$build_dir/meson-dist/wayland-$version-announce.eml" +archive_url="https://gitlab.freedesktop.org/wayland/$name/-/releases/$version/downloads/$archive_name" +announce_path="$build_dir/meson-dist/$name-$version-announce.eml" cat >"$announce_path" < -Subject: [ANNOUNCE] wayland $version +Subject: [ANNOUNCE] $name $version `git shortlog --no-merges "$prev_version.."` @@ -59,7 +65,7 @@ EOF echo "Release announcement written to $announce_path" -echo -n "Release wayland $version? [y/N] " +echo -n "Release $name $version? [y/N] " read answer if [ "$answer" != "y" ]; then exit 1 From 1db6153cc2040849ac4bf38c4660905441e56c01 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 8 Sep 2022 10:36:28 +0200 Subject: [PATCH 0879/1152] util: name function typedef arguments Doxygen doesn't support documenting unnamed function arguments. Fixes the following warnings: src/wayland-util.h:697: warning: argument 'const' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'void' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'void' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'uint32_t' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'const' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'struct' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'wl_message' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'union' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'wl_argument' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:725: warning: argument 'const' of command @param is not found in the argument list of wl_log_func_t(const char *, va_list) src/wayland-util.h:725: warning: argument 'char' of command @param is not found in the argument list of wl_log_func_t(const char *, va_list) src/wayland-util.h:725: warning: argument 'va_list' of command @param is not found in the argument list of wl_log_func_t(const char *, va_list) src/wayland-util.h:697: warning: argument 'const' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'void' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'void' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'uint32_t' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'const' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'struct' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'wl_message' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'union' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:697: warning: argument 'wl_argument' of command @param is not found in the argument list of wl_dispatcher_func_t(const void *, void *, uint32_t, const struct wl_message *, union wl_argument *) src/wayland-util.h:725: warning: argument 'const' of command @param is not found in the argument list of wl_log_func_t(const char *, va_list) src/wayland-util.h:725: warning: argument 'char' of command @param is not found in the argument list of wl_log_func_t(const char *, va_list) src/wayland-util.h:725: warning: argument 'va_list' of command @param is not found in the argument list of wl_log_func_t(const char *, va_list) Signed-off-by: Simon Ser --- src/wayland-util.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 4d59231f..b4cdcfad 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -707,17 +707,17 @@ union wl_argument { * corresponding to the callback. The final argument is an array of arguments * received from the other process via the wire protocol. * - * \param "const void *" Dispatcher-specific implementation data - * \param "void *" Callback invocation target (wl_proxy or `wl_resource`) - * \param uint32_t Callback opcode - * \param "const struct wl_message *" Callback message signature - * \param "union wl_argument *" Array of received arguments + * \param user_data Dispatcher-specific implementation data + * \param target Callback invocation target (wl_proxy or `wl_resource`) + * \param opcode Callback opcode + * \param msg Callback message signature + * \param args Array of received arguments * * \return 0 on success, or -1 on failure */ -typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, - const struct wl_message *, - union wl_argument *); +typedef int (*wl_dispatcher_func_t)(const void *user_data, void *target, + uint32_t opcode, const struct wl_message *msg, + union wl_argument *args); /** * Log function type alias @@ -736,14 +736,14 @@ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, * \note Take care to not confuse this with `wl_protocol_logger_func_t`, which * is a specific server-side logger for requests and events. * - * \param "const char *" String to write to the log, containing optional format - * specifiers - * \param "va_list" Variable argument list + * \param fmt String to write to the log, containing optional format + * specifiers + * \param args Variable argument list * * \sa wl_log_set_handler_client * \sa wl_log_set_handler_server */ -typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0); +typedef void (*wl_log_func_t)(const char *fmt, va_list args) WL_PRINTF(1, 0); /** * Return value of an iterator function From 7d78ea5628d5da8f05bb279a06f8169151da4f9b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 8 Sep 2022 10:37:52 +0200 Subject: [PATCH 0880/1152] server: don't document void return values Fixes the following warnings: src/wayland-server.c:1152: warning: documented empty return type of wl_display::wl_display_destroy src/wayland-server.c:1193: warning: documented empty return type of wl_display::wl_display_set_global_filter Signed-off-by: Simon Ser --- src/wayland-server.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index a44982fb..617d6377 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1150,7 +1150,6 @@ wl_socket_alloc(void) /** Destroy Wayland display object. * * \param display The Wayland display object which should be destroyed. - * \return None. * * This function emits the wl_display destroy signal, releases * all the sockets added to this display, free's all the globals associated @@ -1193,7 +1192,6 @@ wl_display_destroy(struct wl_display *display) * \param display The Wayland display object. * \param filter The global filter function. * \param data User data to be associated with the global filter. - * \return None. * * Set a filter for the wl_display to advertise or hide global objects * to clients. From 2d5acfa5c3f4a184072171b0ed9673abd55a9496 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 8 Sep 2022 10:38:54 +0200 Subject: [PATCH 0881/1152] cursor: make param names match with documentation There was a mismatch here. Use a good-looking function param name because that's what will show up in docs. Use an abbreviation inside the function. Fixes the following warnings: cursor/wayland-cursor.c:504: warning: argument 'cursor' of command @param is not found in the argument list of wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) cursor/wayland-cursor.c:504: warning: The following parameter of wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) is not documented: parameter '_cursor' cursor/wayland-cursor.c:452: warning: argument 'cursor' of command @param is not found in the argument list of wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, uint32_t *duration) cursor/wayland-cursor.c:452: warning: The following parameter of wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, uint32_t *duration) is not documented: parameter '_cursor' cursor/wayland-cursor.c:147: warning: argument 'image' of command @param is not found in the argument list of wl_cursor_image_get_buffer(struct wl_cursor_image *_img) cursor/wayland-cursor.c:147: warning: The following parameter of wl_cursor_image_get_buffer(struct wl_cursor_image *_img) is not documented: parameter '_img' cursor/wayland-cursor.c:504: warning: argument 'cursor' of command @param is not found in the argument list of wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) cursor/wayland-cursor.c:504: warning: The following parameter of wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) is not documented: parameter '_cursor' cursor/wayland-cursor.c:452: warning: argument 'cursor' of command @param is not found in the argument list of wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, uint32_t *duration) cursor/wayland-cursor.c:452: warning: The following parameter of wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, uint32_t *duration) is not documented: parameter '_cursor' cursor/wayland-cursor.c:147: warning: argument 'image' of command @param is not found in the argument list of wl_cursor_image_get_buffer(struct wl_cursor_image *_img) cursor/wayland-cursor.c:147: warning: The following parameter of wl_cursor_image_get_buffer(struct wl_cursor_image *_img) is not documented: parameter '_img' Signed-off-by: Simon Ser --- cursor/wayland-cursor.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 3518aa44..156f0a80 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -151,32 +151,32 @@ struct cursor { * the returned buffer. */ WL_EXPORT struct wl_buffer * -wl_cursor_image_get_buffer(struct wl_cursor_image *_img) +wl_cursor_image_get_buffer(struct wl_cursor_image *image) { - struct cursor_image *image = (struct cursor_image *) _img; - struct wl_cursor_theme *theme = image->theme; + struct cursor_image *img = (struct cursor_image *) image; + struct wl_cursor_theme *theme = img->theme; - if (!image->buffer) { - image->buffer = + if (!img->buffer) { + img->buffer = wl_shm_pool_create_buffer(theme->pool->pool, - image->offset, - _img->width, _img->height, - _img->width * 4, + img->offset, + image->width, image->height, + image->width * 4, WL_SHM_FORMAT_ARGB8888); }; - return image->buffer; + return img->buffer; } static void -wl_cursor_image_destroy(struct wl_cursor_image *_img) +wl_cursor_image_destroy(struct wl_cursor_image *image) { - struct cursor_image *image = (struct cursor_image *) _img; + struct cursor_image *img = (struct cursor_image *) image; - if (image->buffer) - wl_buffer_destroy(image->buffer); + if (img->buffer) + wl_buffer_destroy(img->buffer); - free(image); + free(img); } static void @@ -461,21 +461,21 @@ wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, * given time in the cursor animation. */ WL_EXPORT int -wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, +wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time, uint32_t *duration) { - struct cursor *cursor = (struct cursor *) _cursor; + struct cursor *cur = (struct cursor *) cursor; uint32_t t; int i; - if (cursor->cursor.image_count == 1 || cursor->total_delay == 0) { + if (cur->cursor.image_count == 1 || cur->total_delay == 0) { if (duration) *duration = 0; return 0; } i = 0; - t = time % cursor->total_delay; + t = time % cur->total_delay; /* If there is a 0 delay in the image set then this * loop breaks on it and we display that cursor until @@ -484,8 +484,8 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, * seen one in a cursor file, we haven't bothered to * "fix" this. */ - while (t - cursor->cursor.images[i]->delay < t) - t -= cursor->cursor.images[i++]->delay; + while (t - cur->cursor.images[i]->delay < t) + t -= cur->cursor.images[i++]->delay; if (!duration) return i; @@ -493,10 +493,10 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, /* Make sure we don't accidentally tell the caller this is * a static cursor image. */ - if (t >= cursor->cursor.images[i]->delay) + if (t >= cur->cursor.images[i]->delay) *duration = 1; else - *duration = cursor->cursor.images[i]->delay - t; + *duration = cur->cursor.images[i]->delay - t; return i; } @@ -510,7 +510,7 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, * given time in the cursor animation. */ WL_EXPORT int -wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) +wl_cursor_frame(struct wl_cursor *cursor, uint32_t time) { - return wl_cursor_frame_and_duration(_cursor, time, NULL); + return wl_cursor_frame_and_duration(cursor, time, NULL); } From e1053607830719c28fe8c189d9e5bd3a799aaa0b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 8 Sep 2022 12:26:12 +0200 Subject: [PATCH 0882/1152] ci: set ASAN_OPTIONS=detect_odr_violation=0 Signed-off-by: Simon Ser References: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/154 --- .gitlab-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index db5c9c30..dc1b006a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -156,6 +156,8 @@ armv7-debian-container_prep: .build-env: variables: MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined" + # See https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/154 + ASAN_OPTIONS: "detect_odr_violation=0" before_script: - export BUILD_ID="wayland-$CI_JOB_NAME" - export PREFIX="${CI_PROJECT_DIR}/prefix-${BUILD_ID}" @@ -191,7 +193,7 @@ armv7-debian-container_prep: # for every single subtest. For now, in order to get AArch64 builds and # tests into CI, just assume that we're not going to leak any more on # AArch64 than we would on ARMv7 or x86-64. - ASAN_OPTIONS: "detect_leaks=0" + ASAN_OPTIONS: "detect_leaks=0,detect_odr_violation=0" tags: - aarch64 needs: From 985ab55d59db45ea62795c76dff5949343e86b2f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 8 Sep 2022 11:41:15 +0200 Subject: [PATCH 0883/1152] ci: upgrade images Upgrade Debian to bullseye and FreeBSD to 13.1. FreeBSD 13.0 is not supported anymore, and this ensures we still build on fresh images. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc1b006a..f7f74ec4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ # API changes. If you need new features from ci-templates you must bump # this to the current SHA you require from the ci-templates repo, however # be aware that you may need to account for API changes when doing so. -.templates_sha: &template_sha 567700e483aabed992d0a4fea84994a0472deff6 # see https://docs.gitlab.com/ee/ci/yaml/#includefile +.templates_sha: &template_sha d5aa3941aa03c2f716595116354fb81eb8012acb # see https://docs.gitlab.com/ee/ci/yaml/#includefile include: - project: 'freedesktop/ci-templates' @@ -72,12 +72,12 @@ stages: .os-debian: variables: BUILD_OS: debian - FDO_DISTRIBUTION_VERSION: buster + FDO_DISTRIBUTION_VERSION: bullseye FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.56.0' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2022-02-05.0" + FDO_DISTRIBUTION_TAG: "2022-08-08.0" .debian-x86_64: extends: @@ -301,11 +301,11 @@ armv7-release-debian-build: .os-freebsd: variables: BUILD_OS: freebsd - FDO_DISTRIBUTION_VERSION: "13.0" + FDO_DISTRIBUTION_VERSION: "13.1" FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2021-08-05.0" + FDO_DISTRIBUTION_TAG: "2022-09-08.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. MESON_ARGS: "-Ddocumentation=false" From c2c6ef9cbe7177ccbfd06d5da3a97da27d0b4368 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Sep 2022 09:11:18 +0200 Subject: [PATCH 0884/1152] protocol: mention protocol error name in wl_subcompositor.get_subsurface Let's be explicit here. Signed-off-by: Simon Ser --- protocol/wayland.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 10781cf1..a633bcdb 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2870,8 +2870,8 @@ plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it - must not have an existing wl_subsurface object. Otherwise a protocol - error is raised. + must not have an existing wl_subsurface object. Otherwise the + bad_surface protocol error is raised. Adding sub-surfaces to a parent is a double-buffered operation on the parent (see wl_surface.commit). The effect of adding a sub-surface From b9632822b73b982669a2a59e02b2a98c2f7b47dd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Sep 2022 09:18:47 +0200 Subject: [PATCH 0885/1152] protocol: add wl_compositor.error.bad_parent This forbids loops in sub-surface trees. Signed-off-by: Simon Ser --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index a633bcdb..99732c57 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2861,6 +2861,8 @@ + @@ -2878,6 +2880,10 @@ becomes visible on the next time the state of the parent surface is applied. + The parent surface must not be one of the child surface's descendants, + and the parent must be different from the child surface, otherwise the + bad_parent protocol error is raised. + This request modifies the behaviour of wl_surface.commit request on the sub-surface, see the documentation on wl_subsurface interface. From e886b456aba8b502e599b555b27b09e889bc3eb5 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 21 Jul 2022 10:50:30 +0100 Subject: [PATCH 0886/1152] tests: Use bool for client test A 0/1-only int is a bool. Signed-off-by: Daniel Stone --- tests/client-test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/client-test.c b/tests/client-test.c index 960cfa95..d75e009b 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -40,7 +40,7 @@ struct client_destroy_listener { struct wl_listener listener; - int done; + bool done; }; static void @@ -49,7 +49,7 @@ client_destroy_notify(struct wl_listener *l, void *data) struct client_destroy_listener *listener = wl_container_of(l, listener, listener); - listener->done = 1; + listener->done = true; } TEST(client_destroy_listener) @@ -66,14 +66,14 @@ TEST(client_destroy_listener) assert(client); a.listener.notify = client_destroy_notify; - a.done = 0; + a.done = false; wl_client_add_destroy_listener(client, &a.listener); assert(wl_client_get_destroy_listener(client, client_destroy_notify) == &a.listener); b.listener.notify = client_destroy_notify; - b.done = 0; + b.done = false; wl_client_add_destroy_listener(client, &b.listener); wl_list_remove(&a.listener.link); From 51d788de5b5b3443fa1ca71115d16a53281c5ed9 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 21 Jul 2022 11:07:04 +0100 Subject: [PATCH 0887/1152] wayland-server: Add wl_client_add_destroy_late_listener A late-destroy listener for a client is called after all the client's resources have been destroyed and the destroy callbacks emitted. This lives in parallel to the existing client destroy listener, called immediately before the client's objects get destroyed. Signed-off-by: Daniel Stone Fixes: wayland/wayland#207 --- src/wayland-server-core.h | 8 ++++++++ src/wayland-server.c | 42 +++++++++++++++++++++++++++++++++++++++ tests/client-test.c | 24 ++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 7a1375f8..d9917a0b 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -330,6 +330,14 @@ struct wl_listener * wl_client_get_destroy_listener(struct wl_client *client, wl_notify_func_t notify); +void +wl_client_add_destroy_late_listener(struct wl_client *client, + struct wl_listener *listener); + +struct wl_listener * +wl_client_get_destroy_late_listener(struct wl_client *client, + wl_notify_func_t notify); + struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id); diff --git a/src/wayland-server.c b/src/wayland-server.c index 617d6377..ee53f764 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -79,6 +79,7 @@ struct wl_client { struct wl_list link; struct wl_map objects; struct wl_priv_signal destroy_signal; + struct wl_priv_signal destroy_late_signal; pid_t pid; uid_t uid; gid_t gid; @@ -547,6 +548,7 @@ wl_client_create(struct wl_display *display, int fd) goto err_map; wl_priv_signal_init(&client->destroy_signal); + wl_priv_signal_init(&client->destroy_late_signal); if (bind_display(client, display) < 0) goto err_map; @@ -864,6 +866,17 @@ wl_resource_get_class(struct wl_resource *resource) return resource->object.interface->name; } +/** + * Add a listener to be called at the beginning of wl_client destruction + * + * The listener provided will be called when wl_client destroy has begun, + * before any of that client's resources have been destroyed. + * + * There is no requirement to remove the link of the wl_listener when the + * signal is emitted. + * + * \memberof wl_client + */ WL_EXPORT void wl_client_add_destroy_listener(struct wl_client *client, struct wl_listener *listener) @@ -878,6 +891,32 @@ wl_client_get_destroy_listener(struct wl_client *client, return wl_priv_signal_get(&client->destroy_signal, notify); } +/** + * Add a listener to be called at the end of wl_client destruction + * + * The listener provided will be called when wl_client destroy is nearly + * complete, after all of that client's resources have been destroyed. + * + * There is no requirement to remove the link of the wl_listener when the + * signal is emitted. + * + * \memberof wl_client + * \since 1.22.0 + */ +WL_EXPORT void +wl_client_add_destroy_late_listener(struct wl_client *client, + struct wl_listener *listener) +{ + wl_priv_signal_add(&client->destroy_late_signal, listener); +} + +WL_EXPORT struct wl_listener * +wl_client_get_destroy_late_listener(struct wl_client *client, + wl_notify_func_t notify) +{ + return wl_priv_signal_get(&client->destroy_late_signal, notify); +} + WL_EXPORT void wl_client_destroy(struct wl_client *client) { @@ -890,6 +929,9 @@ wl_client_destroy(struct wl_client *client) wl_map_release(&client->objects); wl_event_source_remove(client->source); close(wl_connection_destroy(client->connection)); + + wl_priv_signal_final_emit(&client->destroy_late_signal, client); + wl_list_remove(&client->link); wl_list_remove(&client->resource_created_signal.listener_list); free(client); diff --git a/tests/client-test.c b/tests/client-test.c index d75e009b..01ebc4ec 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -41,6 +41,8 @@ struct client_destroy_listener { struct wl_listener listener; bool done; + struct wl_listener late_listener; + bool late_done; }; static void @@ -49,9 +51,20 @@ client_destroy_notify(struct wl_listener *l, void *data) struct client_destroy_listener *listener = wl_container_of(l, listener, listener); + assert(!listener->late_done); listener->done = true; } +static void +client_late_destroy_notify(struct wl_listener *l, void *data) +{ + struct client_destroy_listener *listener = + wl_container_of(l, listener, late_listener); + + assert(listener->done); + listener->late_done = true; +} + TEST(client_destroy_listener) { struct wl_display *display; @@ -67,21 +80,32 @@ TEST(client_destroy_listener) a.listener.notify = client_destroy_notify; a.done = false; + a.late_listener.notify = client_late_destroy_notify; + a.late_done = false; wl_client_add_destroy_listener(client, &a.listener); + wl_client_add_destroy_late_listener(client, &a.late_listener); assert(wl_client_get_destroy_listener(client, client_destroy_notify) == &a.listener); + assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) == + &a.late_listener); b.listener.notify = client_destroy_notify; b.done = false; + b.late_listener.notify = client_late_destroy_notify; + b.late_done = false; wl_client_add_destroy_listener(client, &b.listener); + wl_client_add_destroy_late_listener(client, &b.late_listener); wl_list_remove(&a.listener.link); + wl_list_remove(&a.late_listener.link); wl_client_destroy(client); assert(!a.done); + assert(!a.late_done); assert(b.done); + assert(b.late_done); close(s[0]); close(s[1]); From 86d73b2da221bc9ca059195af4c97297fd5221c6 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 21 Jul 2022 11:18:48 +0100 Subject: [PATCH 0888/1152] tests: Ensure resource vs. client destroy handler order Make sure that the client destroy handler runs strictly before the resource destroy handler, which runs strictly before the client late-destroy handler. Signed-off-by: Daniel Stone --- tests/client-test.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/client-test.c b/tests/client-test.c index 01ebc4ec..47be83fc 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -43,6 +43,8 @@ struct client_destroy_listener { bool done; struct wl_listener late_listener; bool late_done; + struct wl_listener resource_listener; + bool resource_done; }; static void @@ -51,8 +53,20 @@ client_destroy_notify(struct wl_listener *l, void *data) struct client_destroy_listener *listener = wl_container_of(l, listener, listener); - assert(!listener->late_done); listener->done = true; + assert(!listener->resource_done); + assert(!listener->late_done); +} + +static void +client_resource_destroy_notify(struct wl_listener *l, void *data) +{ + struct client_destroy_listener *listener = + wl_container_of(l, listener, resource_listener); + + assert(listener->done); + listener->resource_done = true; + assert(!listener->late_done); } static void @@ -62,6 +76,7 @@ client_late_destroy_notify(struct wl_listener *l, void *data) wl_container_of(l, listener, late_listener); assert(listener->done); + assert(listener->resource_done); listener->late_done = true; } @@ -69,6 +84,7 @@ TEST(client_destroy_listener) { struct wl_display *display; struct wl_client *client; + struct wl_resource *resource; struct client_destroy_listener a, b; int s[2]; @@ -78,33 +94,47 @@ TEST(client_destroy_listener) client = wl_client_create(display, s[0]); assert(client); + resource = wl_resource_create(client, &wl_callback_interface, 1, 0); + assert(resource); + a.listener.notify = client_destroy_notify; a.done = false; + a.resource_listener.notify = client_resource_destroy_notify; + a.resource_done = false; a.late_listener.notify = client_late_destroy_notify; a.late_done = false; wl_client_add_destroy_listener(client, &a.listener); + wl_resource_add_destroy_listener(resource, &a.resource_listener); wl_client_add_destroy_late_listener(client, &a.late_listener); assert(wl_client_get_destroy_listener(client, client_destroy_notify) == &a.listener); + assert(wl_resource_get_destroy_listener(resource, client_resource_destroy_notify) == + &a.resource_listener); assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) == &a.late_listener); b.listener.notify = client_destroy_notify; b.done = false; + b.resource_listener.notify = client_resource_destroy_notify; + b.resource_done = false; b.late_listener.notify = client_late_destroy_notify; b.late_done = false; wl_client_add_destroy_listener(client, &b.listener); + wl_resource_add_destroy_listener(resource, &b.resource_listener); wl_client_add_destroy_late_listener(client, &b.late_listener); wl_list_remove(&a.listener.link); + wl_list_remove(&a.resource_listener.link); wl_list_remove(&a.late_listener.link); wl_client_destroy(client); assert(!a.done); + assert(!a.resource_done); assert(!a.late_done); assert(b.done); + assert(b.resource_done); assert(b.late_done); close(s[0]); From 68dfa1183f937a9a34d0a8582e4ffe5eace4a32d Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 15 Oct 2022 20:05:34 +0300 Subject: [PATCH 0889/1152] protocol: remove wl_subsurface lifetime contradiction This statement assumes that a wl_surface can be destroyed before the corresponding wl_subsurface, which is not true, as wl_surface description explicitly states that the role object must be destroyed before the wl_surface itself. Signed-off-by: Kirill Primak --- protocol/wayland.xml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 99732c57..6589d5e8 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2938,12 +2938,10 @@ synchronized mode, and then assume that all its child and grand-child sub-surfaces are synchronized, too, without explicitly setting them. - If the wl_surface associated with the wl_subsurface is destroyed, the - wl_subsurface object becomes inert. Note, that destroying either object - takes effect immediately. If you need to synchronize the removal - of a sub-surface to the parent surface update, unmap the sub-surface - first by attaching a NULL wl_buffer, update parent, and then destroy - the sub-surface. + Destroying a sub-surface takes effect immediately. If you need to + synchronize the removal of a sub-surface to the parent surface update, + unmap the sub-surface first by attaching a NULL wl_buffer, update parent, + and then destroy the sub-surface. If the parent wl_surface object is destroyed, the sub-surface is unmapped. From 0dc23e380a59fcf8a670273dc65816c2cc6de472 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 15 Oct 2022 20:26:42 +0300 Subject: [PATCH 0890/1152] protocol: add defunct_role_object error This commit adds wl_surface.defunct_role_object error, which has semantics similar to xdg_wm_base.defunct_surfaces error, and is sent when a client destroys a surface while the corresponding role object still exists. Signed-off-by: Kirill Primak --- protocol/wayland.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 6589d5e8..a94e85c2 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1384,8 +1384,9 @@ that this request gives a role to a wl_surface. Often, this request also creates a new protocol object that represents the role and adds additional functionality to wl_surface. When a - client wants to destroy a wl_surface, they must destroy this 'role - object' before the wl_surface. + client wants to destroy a wl_surface, they must destroy this role + object before the wl_surface, otherwise a defunct_role_object error is + sent. Destroying the role object does not remove the role from the wl_surface, but it may stop the wl_surface from "playing the role". @@ -1405,6 +1406,8 @@ + From 7f1c51a55613350488fa88f283462fca18f533a1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Dec 2022 18:29:23 +0100 Subject: [PATCH 0891/1152] protocol: add note about wl_buffer/wl_callback version This is an exception which can be confusing. Add an explicit note about it in the protocol text. Signed-off-by: Simon Ser --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index a94e85c2..440ecd8f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -177,6 +177,9 @@ Clients can handle the 'done' event to get notified when the related request is done. + + Note, because wl_callback objects are created from multiple independent + factory interfaces, the wl_callback interface is frozen at version 1. @@ -453,6 +456,9 @@ If the buffer uses a format that has an alpha channel, the alpha channel is assumed to be premultiplied in the color channels unless otherwise specified. + + Note, because wl_buffer objects are created from multiple independent + factory interfaces, the wl_buffer interface is frozen at version 1. From 41aed7a38a928863d5759ac2a93251d35aa1f657 Mon Sep 17 00:00:00 2001 From: Fergus Dall Date: Fri, 23 Sep 2022 07:58:13 +1000 Subject: [PATCH 0892/1152] scanner: Fix undefined behavior around qsort According to clang, qsort cannot be passed a null pointer, even if the size is specified to be zero. The scanner can hit this while trying to sort forward declarations if it happens to be building a protocol file that doesn't require any, either in the header or the source. Signed-off-by: Fergus Dall --- src/scanner.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index da8adea4..c512d231 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1634,7 +1634,9 @@ emit_header(struct protocol *protocol, enum side side) *p = i->name; } - qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); + if (types.size > 0) + qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); + prev = NULL; wl_array_for_each(p, &types) { if (prev && strcmp(*p, prev) == 0) @@ -1844,7 +1846,10 @@ emit_code(struct protocol *protocol, enum visibility vis) emit_types_forward_declarations(protocol, &i->request_list, &types); emit_types_forward_declarations(protocol, &i->event_list, &types); } - qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); + + if (types.size > 0) + qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); + prev = NULL; wl_array_for_each(p, &types) { if (prev && strcmp(*p, prev) == 0) From b27961e48d83203e699905b339d2f290c8379cc2 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Wed, 14 Dec 2022 14:33:42 +0200 Subject: [PATCH 0893/1152] release.sh: Don't push *all* tags Rather than trying to push all possible tags just push the one created for that release. Signed-off-by: Marius Vlad --- release.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/release.sh b/release.sh index 697bf40a..8e843f56 100755 --- a/release.sh +++ b/release.sh @@ -49,6 +49,9 @@ sha256="$(cd $build_dir/meson-dist && sha256sum $archive_name)" sha512="$(cd $build_dir/meson-dist && sha512sum $archive_name)" archive_url="https://gitlab.freedesktop.org/wayland/$name/-/releases/$version/downloads/$archive_name" announce_path="$build_dir/meson-dist/$name-$version-announce.eml" +current_branch=$(git branch --show-current) +remote_name=$(git config --get branch.${current_branch}.remote) + cat >"$announce_path" < Subject: [ANNOUNCE] $name $version @@ -72,5 +75,5 @@ if [ "$answer" != "y" ]; then fi git tag -s -m "$version" "$version" -git push --tags +git push "$remote_name" "$version" glab release create "$version" "$archive_path"* --notes "" From 9700155edaae37bf91b55b58c1c2adf2ed142282 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Thu, 20 Oct 2022 23:31:33 +0200 Subject: [PATCH 0894/1152] protocol: wl_subsurface::destroy does not remove the role Role assigned to wl_surface cannot be removed. Delete contradicting text from wl_subsurface::destroy documentation. Signed-off-by: Mikhail Gusarov --- protocol/wayland.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 440ecd8f..6702bede 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2961,8 +2961,7 @@ The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association - to the parent is deleted, and the wl_surface loses its role as - a sub-surface. The wl_surface is unmapped immediately. + to the parent is deleted. The wl_surface is unmapped immediately. From be31c5a8c852a57007f9a4115bd3e082c089acf1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 24 Jan 2023 23:51:57 +0100 Subject: [PATCH 0895/1152] server: fail on global name overflow display->id is initialized to 1, making 0 a convenient value to indicate an invalid global name. Make sure to not return a zero global name on overflow. Moreover, if we wrap around, we might cycle back to a global name which is already in-use. Signed-off-by: Simon Ser --- src/wayland-server.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index ee53f764..f7e0e6b2 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1285,6 +1285,11 @@ wl_global_create(struct wl_display *display, return NULL; } + if (display->id >= UINT32_MAX) { + wl_log("wl_global_create: ran out of global names\n"); + return NULL; + } + global = zalloc(sizeof *global); if (global == NULL) return NULL; From 83e9c9e117acdf104a9d33838d99a4025a647dfe Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 24 Jan 2023 23:55:29 +0100 Subject: [PATCH 0896/1152] server: rename wl_display.id to next_global_name This is much more descriptive. This value is a counter incremented each time a new global is created. Signed-off-by: Simon Ser --- src/wayland-server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index f7e0e6b2..0e15da3a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -91,7 +91,7 @@ struct wl_display { struct wl_event_loop *loop; int run; - uint32_t id; + uint32_t next_global_name; uint32_t serial; struct wl_list registry_resource_list; @@ -1139,7 +1139,7 @@ wl_display_create(void) wl_priv_signal_init(&display->destroy_signal); wl_priv_signal_init(&display->create_client_signal); - display->id = 1; + display->next_global_name = 1; display->serial = 0; display->global_filter = NULL; @@ -1285,7 +1285,7 @@ wl_global_create(struct wl_display *display, return NULL; } - if (display->id >= UINT32_MAX) { + if (display->next_global_name >= UINT32_MAX) { wl_log("wl_global_create: ran out of global names\n"); return NULL; } @@ -1295,7 +1295,7 @@ wl_global_create(struct wl_display *display, return NULL; global->display = display; - global->name = display->id++; + global->name = display->next_global_name++; global->interface = interface; global->version = version; global->data = data; From 9afab91d212164b56c7eefd234c798fc59ae3fd8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 28 Mar 2022 19:58:04 +0200 Subject: [PATCH 0897/1152] protocol: add wl_surface.preferred_buffer_scale Right now, clients need to bind to wl_output globals, listen to wl_output.scale, listen to wl_surface.enter/leave, pick the highest scale factor. This is an issue because it breaks Wayland's "policy, not mechanism" motto. Clients take the decision of which scale to use depending on the outputs they're on, compositors have no say in this (apart from faking output events, which isn't great). This commit introduces a new wl_surface.preferred_buffer_scale event to allow compositors to directly indicate the preferred scale factor for each surface. This unlocks features which require dynamically changing the scale such as: - Accessibility features such as screen magnifier - In a VR environment, render surfaces close to the eye at a higher scale - HiDPI screenshots on LoDPI screens Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/271 --- protocol/wayland.xml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 6702bede..c0816f66 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -190,7 +190,7 @@ - + A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple @@ -1358,7 +1358,7 @@ - + A surface is a rectangular area that may be displayed on zero or more outputs, and shown any number of times at the compositor's @@ -1795,6 +1795,21 @@ + + + + + + This event indicates the preferred buffer scale for this surface. It is + sent whenever the compositor's preference changes. + + It is intended that scaling aware clients use this event to scale their + content and use wl_surface.set_buffer_scale to indicate the scale they + have rendered with. This allows clients to supply a higher detail + buffer. + + + From d443241635cf86e4fdb91a781ec702bc8828d703 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 26 Nov 2022 13:26:34 +0100 Subject: [PATCH 0898/1152] protocol: add wl_surface.preferred_buffer_transform Same as the new wl_surface.preferred_buffer_scale event but for transform. No version bump needed since the previous commit did that. Signed-off-by: Simon Ser --- protocol/wayland.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index c0816f66..c8ba3aed 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1810,6 +1810,19 @@ + + + + This event indicates the preferred buffer transform for this surface. + It is sent whenever the compositor's preference changes. + + It is intended that transform aware clients use this event to apply the + transform to their content and use wl_surface.set_buffer_transform to + indicate the transform they have rendered with. + + + From d16d39f74a98eb727319c6c026ba4b82054e6269 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Mon, 21 Nov 2022 22:08:15 +0000 Subject: [PATCH 0899/1152] wayland-server: Add method to get global name This is useful for protocol designs where globals need to be referenced in some manner. Signed-off-by: Andri Yngvason --- src/wayland-server-core.h | 4 ++++ src/wayland-server.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index d9917a0b..df958211 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -279,6 +279,10 @@ wl_display_set_global_filter(struct wl_display *display, const struct wl_interface * wl_global_get_interface(const struct wl_global *global); +uint32_t +wl_global_get_name(const struct wl_global *global, + const struct wl_client *client); + uint32_t wl_global_get_version(const struct wl_global *global); diff --git a/src/wayland-server.c b/src/wayland-server.c index 0e15da3a..d51acc62 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1369,6 +1369,23 @@ wl_global_get_interface(const struct wl_global *global) return global->interface; } +/** Get the name of the global. + * + * \param global The global object. + * \param client Client for which to look up the global. + * \return The name of the global, or 0 if the global is not visible to the + * client. + * + * \memberof wl_global + * \since 1.22 + */ +WL_EXPORT uint32_t +wl_global_get_name(const struct wl_global *global, + const struct wl_client *client) +{ + return wl_global_is_visible(client, global) ? global->name : 0; +} + /** Get the version of the given global. * * \param global The global object. From 8ffd7db24f9054a5fdc6d0a25e50d0e4eee95fbb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Feb 2023 19:54:13 +0100 Subject: [PATCH 0900/1152] readme: drop paragraph about Weston There are many Wayland compositors nowadays. Signed-off-by: Simon Ser --- README | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README b/README index ad06dce6..09e630c4 100644 --- a/README +++ b/README @@ -17,10 +17,6 @@ protocol does not handle rendering, which is one of the features that makes wayland so simple. All clients are expected to handle rendering themselves, typically through cairo or OpenGL. -The weston compositor is a reference implementation of a wayland -compositor and the weston repository also includes a few example -clients. - Building the wayland libraries is fairly simple, aside from libffi, they don't have many dependencies: From 20498d9ea18926fe30ce439f92d7440c3079bfa9 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Feb 2023 19:55:42 +0100 Subject: [PATCH 0901/1152] readme: reword website description The website is most useful for docs. Build instructions have been mostly dropped from it: they're better described in downstream projects' READMEs. Signed-off-by: Simon Ser --- README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index 09e630c4..885193d4 100644 --- a/README +++ b/README @@ -25,6 +25,6 @@ they don't have many dependencies: $ meson build/ --prefix=PREFIX $ ninja -C build/ install -where PREFIX is where you want to install the libraries. See -https://wayland.freedesktop.org for more complete build instructions -for wayland, weston, xwayland and various toolkits. +where PREFIX is where you want to install the libraries. + +See https://wayland.freedesktop.org for documentation. From a782152de0f032050e842cce263a8777bd2c9ca3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Feb 2023 19:57:15 +0100 Subject: [PATCH 0902/1152] readme: convert to Markdown Gives us nice links and code blocks. Signed-off-by: Simon Ser --- README => README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename README => README.md (98%) diff --git a/README b/README.md similarity index 98% rename from README rename to README.md index 885193d4..437b39da 100644 --- a/README +++ b/README.md @@ -1,4 +1,4 @@ -What is Wayland? +# Wayland Wayland is a project to define a protocol for a compositor to talk to its clients as well as a library implementation of the protocol. The From 1ef773be76ec0f45312622da7720ae6917bdf789 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Sat, 29 Jul 2017 12:34:49 +0100 Subject: [PATCH 0903/1152] protocol: add wl_pointer's axis relative physical direction This event adds the physical direction of the axis motion, relative to the axis event we get. Right now, when natural scrolling is enabled things like virtual volume sliders move the wrong way round. By adding the axis motion direction, we can have toolkits swap the scroll direction for applicable widgets, getting the right behavior on all widgets. Signed-off-by: Peter Hutterer Reviewed-by: Yong Bakos --- protocol/wayland.xml | 64 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index c8ba3aed..f32a5a53 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1825,7 +1825,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -1958,7 +1958,7 @@ - + The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -2315,9 +2315,65 @@ + + + + + + This specifies the direction of the physical motion that caused a + wl_pointer.axis event, relative to the wl_pointer.axis direction. + + + + + + + + Relative directional information of the entity causing the axis + motion. + + For a wl_pointer.axis event, the wl_pointer.axis_relative_direction + event specifies the movement direction of the entity causing the + wl_pointer.axis event. For example: + - if a user's fingers on a touchpad move down and this + causes a wl_pointer.axis vertical_scroll down event, the physical + direction is 'identical' + - if a user's fingers on a touchpad move down and this causes a + wl_pointer.axis vertical_scroll up scroll up event ('natural + scrolling'), the physical direction is 'inverted'. + + A client may use this information to adjust scroll motion of + components. Specifically, enabling natural scrolling causes the + content to change direction compared to traditional scrolling. + Some widgets like volume control sliders should usually match the + physical direction regardless of whether natural scrolling is + active. This event enables clients to match the scroll direction of + a widget to the physical direction. + + This event does not occur on its own, it is coupled with a + wl_pointer.axis event that represents this axis value. + The protocol guarantees that each axis_relative_direction event is + always followed by exactly one axis event with the same + axis number within the same wl_pointer.frame. Note that the protocol + allows for other events to occur between the axis_relative_direction + and its coupled axis event. + + The axis number is identical to the axis number in the associated + axis event. + + The order of wl_pointer.axis_relative_direction, + wl_pointer.axis_discrete and wl_pointer.axis_source is not + guaranteed. + + + + - + The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -2444,7 +2500,7 @@ - + The wl_touch interface represents a touchscreen associated with a seat. From 2aec8f59e9c02925205ec3b2a2d420b63287c7f5 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 14 Feb 2023 13:33:22 +0100 Subject: [PATCH 0904/1152] protocol: do not change pending x and y when attaching a buffer Attaching a buffer with interface version 5 requires clients to pass zero to x and y but it still affects the pending surface state. Attaching a buffer after a request to offset therefore sets the pending x and y to zero. The intent of version 5 was to allow exactly this sequence of requests to work so let's just make sure the protocol actually spells it out. Signed-off-by: Sebastian Wick --- protocol/wayland.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f32a5a53..07cd6bc6 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1442,8 +1442,9 @@ When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an - 'invalid_offset' error being raised. To achieve equivalent semantics, - use wl_surface.offset. + 'invalid_offset' error being raised. The x and y arguments are ignored + and do not change the pending state. To achieve equivalent semantics, + use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. From 3815803633a6d3bbde7e0cb9118b834e805cb409 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 21 Sep 2022 17:42:58 +0300 Subject: [PATCH 0905/1152] protocol: reorder wl_data_offer.source_actions and wl_data_device.enter Most compositors send the wl_data_offer.source_actions event before the wl_data_device.enter event, i.e. after creation of the data offer. This contradicts to the wayland spec. On the other hand, it's reasonable to send all the information useful to the client before the enter event, rather than send mime types before the enter event and source actions (that don't depend on drop target) after the enter event. On the client side, toolkits such as Qt and GTK already expect to see the source actions before receiving the enter event. Given all of that, this change adjusts the spec to match the behavior observed in the compositors in the wild. Signed-off-by: Vlad Zahorodnii --- protocol/wayland.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 07cd6bc6..0ab57b8b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -630,8 +630,9 @@ This event indicates the actions offered by the data source. It - will be sent right after wl_data_device.enter, or anytime the source - side changes its offered actions through wl_data_source.set_actions. + will be sent immediately after creating the wl_data_offer object, + or anytime the source side changes its offered actions through + wl_data_source.set_actions. From 6cdeae1becef114c064b7021c5dd59d36630975c Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Thu, 20 Oct 2022 23:53:13 +0200 Subject: [PATCH 0906/1152] protocol: Clarify meaning of input region for cursors, DnD icons Input region is ignored for cursors, DnD icons. Current wording implies that this state is temporary, but surfaces never lose the role once assigned, so reword to make it clearer. Signed-off-by: Mikhail Gusarov --- protocol/wayland.xml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 0ab57b8b..10e039d6 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -874,11 +874,8 @@ a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. - The current and pending input regions of the icon wl_surface are - cleared, and wl_surface.set_input_region is ignored until the - wl_surface is no longer used as the icon surface. When the use - as an icon ends, the current and pending input regions become - undefined, and the wl_surface is unmapped. + The input region is ignored for wl_surfaces with the role of a + drag-and-drop icon. @@ -2004,11 +2001,9 @@ pointer surface to this request with new values for hotspot_x and hotspot_y. - The current and pending input regions of the wl_surface are - cleared, and wl_surface.set_input_region is ignored until the - wl_surface is no longer used as the cursor. When the use as a - cursor ends, the current and pending input regions become - undefined, and the wl_surface is unmapped. + The input region is ignored for wl_surfaces with the role of + a cursor. When the use as a cursor ends, the wl_surface is + unmapped. The serial parameter must match the latest wl_pointer.enter serial number sent to the client. Otherwise the request will be From ab526f8d7c80433effd01c1994d50c618c0b7207 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Sep 2022 09:53:39 +0200 Subject: [PATCH 0907/1152] shm: fix segfault when accessing destroyed pool resource With wl_shm_buffer_ref_pool(), it's possible for a wl_shm_pool to outlive its wl_resource. We need to be careful not to access wl_shm_pool.resource if it's been destroyed. Reset resource to NULL in the resource destroy handler, and add NULL checks. Signed-off-by: Simon Ser --- src/wayland-shm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index c4cd390c..8fb657aa 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -109,7 +109,7 @@ shm_pool_grow_mapping(struct wl_shm_pool *pool) data = wl_os_mremap_maymove(pool->mmap_fd, pool->data, &pool->size, pool->new_size, pool->mmap_prot, pool->mmap_flags); - if (pool->size != 0) { + if (pool->size != 0 && pool->resource != NULL) { wl_resource_post_error(pool->resource, WL_SHM_ERROR_INVALID_FD, "leaked old mapping"); @@ -128,9 +128,10 @@ shm_pool_finish_resize(struct wl_shm_pool *pool) data = shm_pool_grow_mapping(pool); if (data == MAP_FAILED) { - wl_resource_post_error(pool->resource, - WL_SHM_ERROR_INVALID_FD, - "failed mremap"); + if (pool->resource != NULL) + wl_resource_post_error(pool->resource, + WL_SHM_ERROR_INVALID_FD, + "failed mremap"); return; } @@ -260,6 +261,7 @@ destroy_pool(struct wl_resource *resource) { struct wl_shm_pool *pool = wl_resource_get_user_data(resource); + pool->resource = NULL; shm_pool_unref(pool, false); } From 674145dc3f621e5a3673714c7527d0e1c5336ab1 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 15 Nov 2022 10:42:55 +0200 Subject: [PATCH 0908/1152] client: Track the proxies attached to a queue Maintain a list of all wl_proxy objects that are attached to a wl_event_queue. We will use this information in upcoming commits to warn about improper object destruction order that can lead to memory errors. Signed-off-by: Alexandros Frantzis --- src/wayland-client.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 90fb9c7d..d3d7a7c7 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -70,10 +70,12 @@ struct wl_proxy { wl_dispatcher_func_t dispatcher; uint32_t version; const char * const *tag; + struct wl_list queue_link; /**< in struct wl_event_queue::proxy_list */ }; struct wl_event_queue { struct wl_list event_list; + struct wl_list proxy_list; /**< struct wl_proxy::queue_link */ struct wl_display *display; }; @@ -221,6 +223,7 @@ static void wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) { wl_list_init(&queue->event_list); + wl_list_init(&queue->proxy_list); queue->display = display; } @@ -435,6 +438,8 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, return NULL; } + wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + return proxy; } @@ -494,6 +499,8 @@ wl_proxy_create_for_id(struct wl_proxy *factory, return NULL; } + wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + return proxy; } @@ -518,6 +525,9 @@ proxy_destroy(struct wl_proxy *proxy) proxy->flags |= WL_PROXY_FLAG_DESTROYED; + wl_list_remove(&proxy->queue_link); + wl_list_init(&proxy->queue_link); + wl_proxy_unref(proxy); } @@ -2335,6 +2345,8 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) { pthread_mutex_lock(&proxy->display->mutex); + wl_list_remove(&proxy->queue_link); + if (queue) { assert(proxy->display == queue->display); proxy->queue = queue; @@ -2342,6 +2354,8 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) proxy->queue = &proxy->display->default_queue; } + wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + pthread_mutex_unlock(&proxy->display->mutex); } @@ -2413,6 +2427,8 @@ wl_proxy_create_wrapper(void *proxy) wrapper->flags = WL_PROXY_FLAG_WRAPPER; wrapper->refcount = 1; + wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link); + pthread_mutex_unlock(&wrapped_proxy->display->mutex); return wrapper; @@ -2434,6 +2450,12 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper) assert(wrapper->refcount == 1); + pthread_mutex_lock(&wrapper->display->mutex); + + wl_list_remove(&wrapper->queue_link); + + pthread_mutex_unlock(&wrapper->display->mutex); + free(wrapper); } From d4d322885349c73f8753cca0c6d7754d2b0b411e Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Thu, 1 Dec 2022 20:02:43 +0200 Subject: [PATCH 0909/1152] tests: Capture the test client log Capture the test client log to a temporary fd, so that is accessible by both the test server process and the test client process. Signed-off-by: Alexandros Frantzis --- tests/sanity-test.c | 61 +++++++++++++++++++++++++++++++++++++++++ tests/test-compositor.c | 41 +++++++++++++++++++++++++-- tests/test-compositor.h | 4 +++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 1a33c127..e614cfb3 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -25,7 +25,9 @@ #include #include +#include #include +#include #include #include @@ -181,6 +183,65 @@ FAIL_TEST(tc_client_fd_leaks_exec) display_destroy(d); } +static char * +map_file(int fd, size_t *len) +{ + char *data; + + *len = lseek(fd, 0, SEEK_END); + data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); + assert(data != MAP_FAILED && "Failed to mmap file"); + + return data; +} + +static void +sanity_client_log(void) +{ + char *log; + size_t log_len; + char *wayland_socket = strdup(getenv("WAYLAND_SOCKET")); + char *xdg_runtime_dir = strdup(getenv("XDG_RUNTIME_DIR")); + + unsetenv("WAYLAND_SOCKET"); + unsetenv("XDG_RUNTIME_DIR"); + + /* Try to connect to the default wayland display, which should fail since + * we have neither WAYLAND_SOCKET nor XDG_RUNTIME_DIR. */ + assert(!wl_display_connect(NULL)); + + /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */ + log = map_file(client_log_fd, &log_len); + assert(strstr(log, "XDG_RUNTIME_DIR")); + munmap(log, log_len); + + /* Reset the environment variables we unset for the test. The test harness + * leak checker cares about the value of WAYLAND_SOCKET during teardown for + * correct fd accounting. */ + setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 0); + setenv("WAYLAND_SOCKET", wayland_socket, 0); + free(xdg_runtime_dir); + free(wayland_socket); +} + +TEST(tc_client_log) +{ + struct display *d = display_create(); + struct client_info *ci; + char *log; + size_t log_len; + + ci = client_create_noarg(d, sanity_client_log); + display_run(d); + + /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */ + log = map_file(ci->log_fd, &log_len); + assert(strstr(log, "XDG_RUNTIME_DIR")); + munmap(log, log_len); + + display_destroy(d); +} + FAIL_TEST(timeout_tst) { test_set_timeout(1); diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 103ddc85..587bc2b0 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -40,6 +40,8 @@ #include "test-runner.h" #include "test-compositor.h" +int client_log_fd = -1; + /* --- Protocol --- */ struct test_compositor; @@ -155,9 +157,21 @@ client_destroyed(struct wl_listener *listener, void *data) ci->wl_client = NULL; } +static void +client_log_handler(const char *fmt, va_list arg) +{ + va_list arg_copy; + + va_copy(arg_copy, arg); + vdprintf(client_log_fd, fmt, arg_copy); + va_end(arg_copy); + + vfprintf(stderr, fmt, arg); +} + static void run_client(void (*client_main)(void *data), void *data, - int wayland_sock, int client_pipe) + int wayland_sock, int client_pipe, int log_fd) { char s[8]; int cur_fds; @@ -173,6 +187,10 @@ run_client(void (*client_main)(void *data), void *data, snprintf(s, sizeof s, "%d", wayland_sock); setenv("WAYLAND_SOCKET", s, 0); + /* Capture the log to the specified file descriptor. */ + client_log_fd = log_fd; + wl_log_set_handler_client(client_log_handler); + cur_fds = count_open_fds(); client_main(data); @@ -188,6 +206,18 @@ run_client(void (*client_main)(void *data), void *data, check_fd_leaks(cur_fds); } +static int +create_log_fd(void) +{ + char logname[] = "/tmp/wayland-tests-log-XXXXXX"; + int log_fd = mkstemp(logname); + + if (log_fd >= 0) + unlink(logname); + + return log_fd; +} + static struct client_info * display_create_client(struct display *d, void (*client_main)(void *data), @@ -199,11 +229,15 @@ display_create_client(struct display *d, pid_t pid; int can_continue = 0; struct client_info *cl; + int log_fd; assert(pipe(pipe_cli) == 0 && "Failed creating pipe"); assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0 && "Failed creating socket pair"); + log_fd = create_log_fd(); + assert(log_fd >= 0 && "Failed to create log fd"); + pid = fork(); assert(pid != -1 && "Fork failed"); @@ -211,10 +245,11 @@ display_create_client(struct display *d, close(sock_wayl[1]); close(pipe_cli[1]); - run_client(client_main, data, sock_wayl[0], pipe_cli[0]); + run_client(client_main, data, sock_wayl[0], pipe_cli[0], log_fd); close(sock_wayl[0]); close(pipe_cli[0]); + close(log_fd); exit(0); } @@ -231,6 +266,7 @@ display_create_client(struct display *d, cl->name = name; cl->pid = pid; cl->pipe = pipe_cli[1]; + cl->log_fd = log_fd; cl->destroy_listener.notify = &client_destroyed; cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]); @@ -407,6 +443,7 @@ display_destroy(struct display *d) } close(cl->pipe); + close(cl->log_fd); free(cl); } diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 7b350fe9..b681b093 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -43,6 +43,7 @@ struct client_info { struct wl_list link; void *data; /* for arbitrary use */ + int log_fd; }; struct display { @@ -106,6 +107,9 @@ void display_post_resume_events(struct display *d); * it then reruns the display. */ void display_resume(struct display *d); +/* The file descriptor containing the client log. This is only valid in the + * test client processes. */ +extern int client_log_fd; struct client_info *client_create_with_name(struct display *d, void (*client_main)(void *data), From 0ba650202e742b23150054cf0740168cd529b010 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 15 Nov 2022 10:50:53 +0200 Subject: [PATCH 0910/1152] client: Warn when a queue is destroyed with attached proxies Log a warning if the queue is destroyed while proxies are still attached, to help developers debug and fix potential memory errors. Signed-off-by: Alexandros Frantzis --- src/wayland-client.c | 16 ++++++++ tests/queue-test.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index d3d7a7c7..f7d7e688 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -301,6 +301,22 @@ wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; + if (!wl_list_empty(&queue->proxy_list)) { + struct wl_proxy *proxy, *tmp; + + wl_log("warning: queue %p destroyed while proxies still " + "attached:\n", queue); + + wl_list_for_each_safe(proxy, tmp, &queue->proxy_list, + queue_link) { + wl_log(" %s@%u still attached\n", + proxy->object.interface->name, + proxy->object.id); + wl_list_remove(&proxy->queue_link); + wl_list_init(&proxy->queue_link); + } + } + while (!wl_list_empty(&queue->event_list)) { closure = wl_container_of(queue->event_list.next, closure, link); diff --git a/tests/queue-test.c b/tests/queue-test.c index 86a36025..f9254f79 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -23,11 +23,14 @@ * SOFTWARE. */ +#define _GNU_SOURCE /* For memrchr */ #include #include #include #include +#include #include +#include #include #include #include @@ -303,6 +306,84 @@ client_test_queue_set_queue_race(void) wl_display_disconnect(display); } +static char * +map_file(int fd, size_t *len) +{ + char *data; + + *len = lseek(fd, 0, SEEK_END); + data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); + assert(data != MAP_FAILED && "Failed to mmap file"); + + return data; +} + +static char * +last_line_of(char *s) +{ + size_t len = strlen(s); + char *last; + + last = memrchr(s, '\n', len); + /* If we found a newline at end of string, find the previous one. */ + if (last && last[1] == 0) + last = memrchr(s, '\n', len - 1); + /* If we have a newline, the last line starts after the newline. + * Otherwise, the whole string is the last line. */ + if (last) + last += 1; + else + last = s; + + return last; +} + +static void +client_test_queue_destroy_with_attached_proxies(void) +{ + struct wl_event_queue *queue; + struct wl_display *display; + struct wl_display *display_wrapper; + struct wl_callback *callback; + char *log; + size_t log_len; + char callback_name[24]; + int ret; + + display = wl_display_connect(NULL); + assert(display); + + /* Pretend we are in a separate thread where a thread-local queue is + * used. */ + queue = wl_display_create_queue(display); + assert(queue); + + /* Create a sync dispatching events on the thread-local queue. */ + display_wrapper = wl_proxy_create_wrapper(display); + assert(display_wrapper); + wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); + callback = wl_display_sync(display_wrapper); + wl_proxy_wrapper_destroy(display_wrapper); + assert(callback != NULL); + + /* Destroy the queue before the attached object. */ + wl_event_queue_destroy(queue); + + /* Check that the log contains some information about the attached + * wl_callback proxy. */ + log = map_file(client_log_fd, &log_len); + ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u", + wl_proxy_get_id((struct wl_proxy *) callback)); + assert(ret > 0 && ret < (int)sizeof(callback_name) && + "callback name creation failed (possibly truncated)"); + assert(strstr(last_line_of(log), callback_name)); + munmap(log, log_len); + + wl_callback_destroy(callback); + + wl_display_disconnect(display); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -382,3 +463,15 @@ TEST(queue_set_queue_race) display_destroy(d); } + +TEST(queue_destroy_with_attached_proxies) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_destroy_with_attached_proxies); + display_run(d); + + display_destroy(d); +} From e09010f470b28353e29a673ad76e813a92e61a1f Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 15 Nov 2022 11:21:37 +0200 Subject: [PATCH 0911/1152] tests: Support tests that check for client failure Add the display_destroy_expect_signal() function to check that test clients exit due to a particular signal. This is useful for checking that clients fail in an expected way. Signed-off-by: Alexandros Frantzis --- tests/test-compositor.c | 22 +++++++++++++++++++--- tests/test-compositor.h | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 587bc2b0..49d76d6d 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -114,7 +114,7 @@ handle_client_destroy(void *data) case CLD_DUMPED: fprintf(stderr, "Client '%s' was killed by signal %d\n", ci->name, status.si_status); - ci->exit_code = status.si_status; + ci->kill_code = status.si_status; break; case CLD_EXITED: if (status.si_status != EXIT_SUCCESS) @@ -425,8 +425,10 @@ display_resume(struct display *d) wl_display_run(d->wl_display); } +/* If signum is 0, expect a successful client exit, otherwise + * expect the client to have been killed by that signal. */ void -display_destroy(struct display *d) +display_destroy_expect_signal(struct display *d, int signum) { struct client_info *cl, *next; int failed = 0; @@ -437,7 +439,15 @@ display_destroy(struct display *d) wl_list_for_each_safe(cl, next, &d->clients, link) { assert(cl->wl_client == NULL); - if (cl->exit_code != 0) { + if (signum != 0 && cl->kill_code != signum) { + ++failed; + fprintf(stderr, + "Client '%s' failed, expecting signal %d, " + "got %d\n", + cl->name, signum, cl->kill_code); + } + else if (signum == 0 && + (cl->kill_code != 0 || cl->exit_code != 0)) { ++failed; fprintf(stderr, "Client '%s' failed\n", cl->name); } @@ -457,6 +467,12 @@ display_destroy(struct display *d) } } +void +display_destroy(struct display *d) +{ + display_destroy_expect_signal(d, 0); +} + /* * --- Client helper functions --- */ diff --git a/tests/test-compositor.h b/tests/test-compositor.h index b681b093..3fb390c2 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -40,6 +40,7 @@ struct client_info { int pipe; pid_t pid; int exit_code; + int kill_code; struct wl_list link; void *data; /* for arbitrary use */ @@ -91,6 +92,7 @@ void noop_request(struct client *); */ struct display *display_create(void); void display_destroy(struct display *d); +void display_destroy_expect_signal(struct display *d, int signum); void display_run(struct display *d); /* This function posts the display_resumed event to all waiting clients, From d72f9007c36f2f8ad2dc26178545e8a7f5b993a0 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 15 Nov 2022 11:44:55 +0200 Subject: [PATCH 0912/1152] client: Abort when trying to add an event to a destroyed queue Detect when we are trying to add an event to a destroyed queue, and abort instead of causing a use-after-free memory error. This situation can occur when an wl_event_queue is destroyed before its attached wl_proxy objects. Signed-off-by: Alexandros Frantzis --- src/wayland-client.c | 5 ++++ tests/queue-test.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index f7d7e688..a50fc18f 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -312,6 +312,7 @@ wl_event_queue_release(struct wl_event_queue *queue) wl_log(" %s@%u still attached\n", proxy->object.interface->name, proxy->object.id); + proxy->queue = NULL; wl_list_remove(&proxy->queue_link); wl_list_init(&proxy->queue_link); } @@ -541,6 +542,7 @@ proxy_destroy(struct wl_proxy *proxy) proxy->flags |= WL_PROXY_FLAG_DESTROYED; + proxy->queue = NULL; wl_list_remove(&proxy->queue_link); wl_list_init(&proxy->queue_link); @@ -1564,6 +1566,9 @@ queue_event(struct wl_display *display, int len) else queue = proxy->queue; + if (!queue) + wl_abort("Tried to add event to destroyed queue\n"); + wl_list_insert(queue->event_list.prev, &closure->link); return size; diff --git a/tests/queue-test.c b/tests/queue-test.c index f9254f79..63abc19c 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "wayland-client.h" #include "wayland-server.h" @@ -384,6 +385,43 @@ client_test_queue_destroy_with_attached_proxies(void) wl_display_disconnect(display); } +static void +client_test_queue_proxy_event_to_destroyed_queue(void) +{ + struct wl_event_queue *queue; + struct wl_display *display; + struct wl_display *display_wrapper; + struct wl_callback *callback; + + display = wl_display_connect(NULL); + assert(display); + + /* Pretend we are in a separate thread where a thread-local queue is + * used. */ + queue = wl_display_create_queue(display); + assert(queue); + + /* Create a sync dispatching events on the thread-local queue. */ + display_wrapper = wl_proxy_create_wrapper(display); + assert(display_wrapper); + wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); + callback = wl_display_sync(display_wrapper); + wl_proxy_wrapper_destroy(display_wrapper); + assert(callback != NULL); + wl_display_flush(display); + + /* Destroy the queue before the attached object. */ + wl_event_queue_destroy(queue); + + /* During this roundtrip we should receive the done event on 'callback', + * try to queue it to the destroyed queue, and abort. */ + wl_display_roundtrip(display); + + wl_callback_destroy(callback); + + wl_display_disconnect(display); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -475,3 +513,26 @@ TEST(queue_destroy_with_attached_proxies) display_destroy(d); } + +TEST(queue_proxy_event_to_destroyed_queue) +{ + struct display *d = display_create(); + struct client_info *ci; + char *client_log; + size_t client_log_len; + + test_set_timeout(2); + + ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue); + display_run(d); + + /* Check that the final line in the log mentions the expected reason + * for the abort. */ + client_log = map_file(ci->log_fd, &client_log_len); + assert(!strcmp(last_line_of(client_log), + "Tried to add event to destroyed queue\n")); + munmap(client_log, client_log_len); + + /* Check that the client aborted. */ + display_destroy_expect_signal(d, SIGABRT); +} From 344d31f871e7ff85137e1e80062367dc3ad7418e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Feb 2023 17:15:31 +0100 Subject: [PATCH 0913/1152] build: bump version to 1.21.91 for the alpha release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index f469756f..8076356f 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.21.90', + version: '1.21.91', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From b01a85dfd5e8cda7170b7ba6fe66fc3800f93990 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 28 Feb 2023 23:42:59 +0200 Subject: [PATCH 0914/1152] client: Do not warn about attached proxies on default queue destruction. If the default queue is being destroyed, the client is disconnecting from the wl_display, so there is no possibility of subsequent events being queued to the destroyed default queue, which is what this warning is about. Note that interacting with (e.g., destroying) a wl_proxy after its wl_display is destroyed is a certain memory error, and this warning will indirectly warn about this issue. However, this memory error should be detected and warned about through a more deliberate mechanism. Signed-off-by: Alexandros Frantzis --- src/wayland-client.c | 14 ++++++---- tests/queue-test.c | 63 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index a50fc18f..054c0c7a 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -304,14 +304,18 @@ wl_event_queue_release(struct wl_event_queue *queue) if (!wl_list_empty(&queue->proxy_list)) { struct wl_proxy *proxy, *tmp; - wl_log("warning: queue %p destroyed while proxies still " - "attached:\n", queue); + if (queue != &queue->display->default_queue) { + wl_log("warning: queue %p destroyed while proxies " + "still attached:\n", queue); + } wl_list_for_each_safe(proxy, tmp, &queue->proxy_list, queue_link) { - wl_log(" %s@%u still attached\n", - proxy->object.interface->name, - proxy->object.id); + if (queue != &queue->display->default_queue) { + wl_log(" %s@%u still attached\n", + proxy->object.interface->name, + proxy->object.id); + } proxy->queue = NULL; wl_list_remove(&proxy->queue_link); wl_list_init(&proxy->queue_link); diff --git a/tests/queue-test.c b/tests/queue-test.c index 63abc19c..41293100 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -308,12 +308,22 @@ client_test_queue_set_queue_race(void) } static char * -map_file(int fd, size_t *len) +maybe_map_file(int fd, size_t *len) { char *data; *len = lseek(fd, 0, SEEK_END); data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); + + return data; +} + +static char * +map_file(int fd, size_t *len) +{ + char *data; + + data = maybe_map_file(fd, len); assert(data != MAP_FAILED && "Failed to mmap file"); return data; @@ -422,6 +432,45 @@ client_test_queue_proxy_event_to_destroyed_queue(void) wl_display_disconnect(display); } +static void +client_test_queue_destroy_default_with_attached_proxies(void) +{ + struct wl_display *display; + struct wl_callback *callback; + char *log; + size_t log_len; + char callback_name[24]; + int ret; + + display = wl_display_connect(NULL); + assert(display); + + /* Create a sync dispatching events on the default queue. */ + callback = wl_display_sync(display); + assert(callback != NULL); + + /* Destroy the default queue (by disconnecting) before the attached + * object. */ + wl_display_disconnect(display); + + /* Check that the log does not contain any warning about the attached + * wl_callback proxy. */ + log = maybe_map_file(client_log_fd, &log_len); + ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u", + wl_proxy_get_id((struct wl_proxy *) callback)); + assert(ret > 0 && ret < (int)sizeof(callback_name) && + "callback name creation failed (possibly truncated)"); + assert(log == MAP_FAILED || strstr(log, callback_name) == NULL); + if (log != MAP_FAILED) + munmap(log, log_len); + + /* HACK: Directly free the memory of the wl_callback proxy to appease + * ASan. We would normally use wl_callback_destroy(), but since we have + * destroyed the associated wl_display, using this function would lead + * to memory errors. */ + free(callback); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -536,3 +585,15 @@ TEST(queue_proxy_event_to_destroyed_queue) /* Check that the client aborted. */ display_destroy_expect_signal(d, SIGABRT); } + +TEST(queue_destroy_default_with_attached_proxies) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_destroy_default_with_attached_proxies); + display_run(d); + + display_destroy(d); +} From 3956948fac5c0bf29ee13fd1c299a47a16c05a6d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Mar 2023 15:14:37 +0100 Subject: [PATCH 0915/1152] client: fix wl_display_disconnect() documentation Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/361 --- src/wayland-client.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 054c0c7a..105f9bed 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1308,8 +1308,9 @@ wl_display_connect(const char *name) * * \param display The display context object * - * Close the connection to \c display and free all resources associated - * with it. + * Close the connection to \c display. The \ref wl_proxy and + * \ref wl_event_queue objects need to be manually destroyed by the caller + * before disconnecting. * * \memberof wl_display */ From 002e1f1d3a2ad65b3f5417c80fd490b966a7eee3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Mar 2023 01:08:44 +0100 Subject: [PATCH 0916/1152] build: bump version to 1.21.92 for the beta release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8076356f..35c3b957 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.21.91', + version: '1.21.92', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From eb19f99a5b237806dc4703645e1fec32f4f94e8c Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Sat, 25 Mar 2023 11:04:32 -0500 Subject: [PATCH 0917/1152] Add a .mailmap file This will let command-line Git tools re-map my name and e-mail address properly. I'm using my personal e-mail address and not my Collabora address because I'm not actively contributing to Wayland anymore and this is mostly for letting people find me should they dig me up in the project history. Signed-off-by: Faith Ekstrand --- .mailmap | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..bdb791e7 --- /dev/null +++ b/.mailmap @@ -0,0 +1,3 @@ +Faith Ekstrand +Faith Ekstrand +Faith Ekstrand From cd036bb7b88907ccc926aeff5cdfc915963bdb9a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Mar 2023 20:02:48 +0200 Subject: [PATCH 0918/1152] build: bump to version 1.21.93 for the RC1 release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 35c3b957..b8b42cca 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.21.92', + version: '1.21.93', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From b2649cb3ee6bd70828a17e50beb16591e6066288 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 4 Apr 2023 09:58:31 +0200 Subject: [PATCH 0919/1152] build: bump to version 1.22.0 for the official release --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b8b42cca..558c7ac5 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.21.93', + version: '1.22.0', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From cdd890a6f8701d44641b215549a856e524229373 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 4 Apr 2023 13:38:18 +0200 Subject: [PATCH 0920/1152] build: re-open main branch for regular development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 558c7ac5..b879df7b 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.22.0', + version: '1.22.90', license: 'MIT', meson_version: '>= 0.56.0', default_options: [ From 307b23626d9fccc4ab9f72b23940f26c54505b0e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 20 Feb 2019 14:03:55 +0100 Subject: [PATCH 0921/1152] protocol: disallow re-using wl_data_source As pointed out in [1], re-using a wl_data_source for multiple start_drag or set_selection requests has bad consequences, because this object has events that allo tracking the state of a selection/drag-and-drop operation. Tracking two operations at the same time isn't possible with this interface. [1]: https://lists.freedesktop.org/archives/wayland-devel/2019-January/039936.html Signed-off-by: Simon Ser Signed-off-by: Daniel Stone --- protocol/wayland.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 10e039d6..17a17690 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -847,6 +847,7 @@ + @@ -876,6 +877,10 @@ The input region is ignored for wl_surfaces with the role of a drag-and-drop icon. + + The given source may not be used in any further set_selection or + start_drag requests. Attempting to reuse a previously-used source + may send a used_source error. @@ -889,6 +894,10 @@ to the data from the source on behalf of the client. To unset the selection, set the source to NULL. + + The given source may not be used in any further set_selection or + start_drag requests. Attempting to reuse a previously-used source + may send a used_source error. From 1e259a255a07cd16b31fc99e6bba3e9368fae6d9 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 9 Aug 2022 19:17:22 +0200 Subject: [PATCH 0922/1152] protocol: improve wl_keyboard focus documentation The compositor must not send any key events while a surface is not focused, but in order to allow for common actions like ctrl+scroll for zooming to work with unfocused surfaces it may do so with modifiers. Signed-off-by: Xaver Hugl --- protocol/wayland.xml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 17a17690..d95e5a2f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2431,8 +2431,10 @@ The leave notification is sent before the enter notification for the new focus. - After this event client must assume that all keys, including modifiers, - are lifted and also it must stop key repeating if there's some going on. + After this event client must assume that no keys are pressed, + it must stop key repeating if there's some going on and until + it receives the next wl_keyboard.modifiers event, the client + must also assume no modifiers are active. @@ -2457,6 +2459,9 @@ If this event produces a change in modifiers, then the resulting wl_keyboard.modifiers event must be sent after this event. + + The compositor must not send this event without a surface of the client + having keyboard focus. @@ -2468,6 +2473,14 @@ Notifies clients that the modifier and/or group state has changed, and it should update its local state. + + The compositor may send this event without a surface of the client + having keyboard focus, for example to tie modifier information to + pointer focus instead. If a modifier event with pressed modifiers is sent + without a prior enter event, the client can assume the modifier state is + valid until it receives the next wl_keyboard.modifiers event. In order to + reset the modifier state again, the compositor can send a + wl_keyboard.modifiers event with no pressed modifiers. From 3bac2e5fb8ee6b02ad09e8e556edd270d7f4de9c Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Tue, 18 Apr 2023 16:39:00 +0100 Subject: [PATCH 0923/1152] event-loop: Handle EINTR and EAGAIN in wl_event_loop_dispatch This fixes an issue where it was not possible to start Gamescope under GDB on some setups. https://github.com/ValveSoftware/gamescope/issues/743 Any signals would cause epoll_wait to return -1 and set errno to EINTR. This also handles the EAGAIN case like the other polling loops in libwayland. Signed-off-by: Joshua Ashton --- src/event-loop.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index 37cf95d3..dd9a9710 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -971,6 +971,57 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop) } } +static int +timespec_to_ms(struct timespec value) +{ + return (value.tv_sec * 1000) + (value.tv_nsec / 1000000); +} + +static struct timespec +ms_to_timespec(int ms) +{ + struct timespec val; + val.tv_sec = ms / 1000; + val.tv_nsec = (ms % 1000) * 1000000; + return val; +} + +static struct timespec +timespec_normalize(struct timespec value) +{ + struct timespec result = value; + + while (result.tv_nsec >= 1000000000) { + result.tv_nsec -= 1000000000; + result.tv_sec++; + } + + while (result.tv_nsec < 0) { + result.tv_nsec += 1000000000; + result.tv_sec--; + } + + return result; +} + +static struct timespec +timespec_add(struct timespec a, struct timespec b) +{ + struct timespec result; + result.tv_sec = a.tv_sec + b.tv_sec; + result.tv_nsec = a.tv_nsec + b.tv_nsec; + return timespec_normalize(result); +} + +static struct timespec +timespec_sub(struct timespec a, struct timespec b) +{ + struct timespec result; + result.tv_sec = a.tv_sec - b.tv_sec; + result.tv_nsec = a.tv_nsec - b.tv_nsec; + return timespec_normalize(result); +} + /** Wait for events and dispatch them * * \param loop The event loop whose sources to wait for. @@ -998,10 +1049,34 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) struct wl_event_source *source; int i, count; bool has_timers = false; + bool use_timeout = timeout > 0; + struct timespec now, end; wl_event_loop_dispatch_idle(loop); - count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout); + if (use_timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + end = timespec_add(now, ms_to_timespec(timeout)); + } + + while (true) { + count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout); + if (count >= 0) + break; /* have events or timeout */ + else if (count < 0 && errno != EINTR && errno != EAGAIN) + break; /* have error */ + + if (use_timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + timeout = timespec_to_ms(timespec_sub(end, now)); + if (timeout <= 0) { + /* too late */ + count = 0; + break; + } + } + } + if (count < 0) return -1; From d40052e083be1e26a4ef628b00fb5d969826164f Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Mon, 27 Mar 2023 21:30:10 -0400 Subject: [PATCH 0924/1152] protocol: add new shm formats This brings the format list up to date with libdrm 2.4.115. Signed-off-by: Manuel Stoeckl --- protocol/wayland.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d95e5a2f..a2a969bf 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -419,6 +419,21 @@ + + + + + + + + + + + + + + + From b1b97e8d348ed3ac9c9c422534bd47bc8fb2d31e Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 25 Feb 2023 15:57:47 -0500 Subject: [PATCH 0925/1152] tests: drop misleading fixed-benchmark Because this benchmark performed wl_fixed_to_double conversions on a long sequence of consecutive integers, the compiler could optimize away the addition performed in wl_fixed_to_double, merging it with the loop iteration code. This made tests/fixed-benchmark.c significantly underestimate the actual cost of the current wl_fixed_to_double implementation. Signed-off-by: Manuel Stoeckl --- tests/fixed-benchmark.c | 107 ---------------------------------------- tests/meson.build | 9 ---- 2 files changed, 116 deletions(-) delete mode 100644 tests/fixed-benchmark.c diff --git a/tests/fixed-benchmark.c b/tests/fixed-benchmark.c deleted file mode 100644 index 277eccec..00000000 --- a/tests/fixed-benchmark.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright © 2012 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include "wayland-private.h" - -volatile double global_d; - -static void -noop_conversion(void) -{ - wl_fixed_t f; - union { - int64_t i; - double d; - } u; - - for (f = 0; f < INT32_MAX; f++) { - u.i = f; - global_d = u.d; - } -} - -static void -magic_conversion(void) -{ - wl_fixed_t f; - - for (f = 0; f < INT32_MAX; f++) - global_d = wl_fixed_to_double(f); -} - -static void -mul_conversion(void) -{ - wl_fixed_t f; - - /* This will get optimized into multiplication by 1/256 */ - for (f = 0; f < INT32_MAX; f++) - global_d = f / 256.0; -} - -double factor = 256.0; - -static void -div_conversion(void) -{ - wl_fixed_t f; - - for (f = 0; f < INT32_MAX; f++) - global_d = f / factor; -} - -static void -benchmark(const char *s, void (*f)(void)) -{ - struct timespec start, stop, elapsed; - - clock_gettime(CLOCK_MONOTONIC, &start); - f(); - clock_gettime(CLOCK_MONOTONIC, &stop); - - elapsed.tv_sec = stop.tv_sec - start.tv_sec; - elapsed.tv_nsec = stop.tv_nsec - start.tv_nsec; - if (elapsed.tv_nsec < 0) { - elapsed.tv_nsec += 1000000000; - elapsed.tv_sec--; - } - printf("benchmarked %s:\t%ld.%09lds\n", - s, elapsed.tv_sec, elapsed.tv_nsec); -} - -int main(void) -{ - benchmark("noop", noop_conversion); - benchmark("magic", magic_conversion); - benchmark("div", div_conversion); - benchmark("mul", mul_conversion); - - return 0; -} diff --git a/tests/meson.build b/tests/meson.build index 5efd6f7a..40e3ab31 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -54,15 +54,6 @@ tests_protocol_c = custom_target( output: 'tests-protocol.c' ) -benchmark( - 'fixed-benchmark', - executable( - 'fixed-benchmark', - 'fixed-benchmark.c', - dependencies: [ test_runner_dep, rt_dep ] - ) -) - executable( 'exec-fd-leak-checker', 'exec-fd-leak-checker.c', From 11b17c1286afac0e6e399986df83721a4ea9487b Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 9 Mar 2023 10:38:15 +0800 Subject: [PATCH 0926/1152] event-loop: optimize timer check logic the 'has_timers' flag can be returned directly without having to track all the ready events when a timer is found ready. Signed-off-by: Yang Wang --- src/event-loop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/event-loop.c b/src/event-loop.c index dd9a9710..c5cc34a6 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -1082,8 +1082,10 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) for (i = 0; i < count; i++) { source = ep[i].data.ptr; - if (source == &loop->timers.base) + if (source == &loop->timers.base) { has_timers = true; + break; + } } if (has_timers) { From 0e0ae7e290f28f4ee4ad807acb955d6b276d9e58 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 May 2023 21:16:25 +0200 Subject: [PATCH 0927/1152] util: simplify wl_fixed_to_double() We can just use a simple division instead of bit operations with magic numbers. Readability matters more than performance here. References: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/296 Signed-off-by: Simon Ser --- src/wayland-util.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index b4cdcfad..272a3c01 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -613,14 +613,7 @@ typedef int32_t wl_fixed_t; static inline double wl_fixed_to_double(wl_fixed_t f) { - union { - double d; - int64_t i; - } u; - - u.i = ((1023LL + 44LL) << 52) + (1LL << 51) + f; - - return u.d - (3LL << 43); + return f / 256.0; } /** From 8f2a33cffcdffcd1d2564c8f495053c5e1d385f7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 18 Apr 2023 17:44:47 +0200 Subject: [PATCH 0928/1152] server: stop wl_display_run() on dispatch error If wl_event_loop_dispatch() fails, we could enter an infinite loop, repeatedly calling a failing wl_event_loop_dispatch() forever. Signed-off-by: Simon Ser --- src/wayland-server.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index d51acc62..51797bf0 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1490,7 +1490,9 @@ wl_display_run(struct wl_display *display) while (display->run) { wl_display_flush_clients(display); - wl_event_loop_dispatch(display->loop, -1); + if (wl_event_loop_dispatch(display->loop, -1) < 0) { + break; + } } } From 2aec19ce41bb970f7ff982b60993e81367a6fc15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 May 2023 16:24:29 +0200 Subject: [PATCH 0929/1152] build: override wayland-scanner dep This allows a parent project to find wayland-scanner. Signed-off-by: Simon Ser --- src/meson.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/meson.build b/src/meson.build index a8a1d2ba..9e61f3d4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -74,6 +74,9 @@ if get_option('scanner') if meson.can_run_host_binaries() meson.override_find_program('wayland-scanner', wayland_scanner) + meson.override_dependency('wayland-scanner', declare_dependency( + variables: { 'wayland_scanner': 'wayland-scanner' }, + )) endif endif From f3026c916ef91d78040913298170d5e538dd6618 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 9 May 2023 13:55:53 +0200 Subject: [PATCH 0930/1152] protocol: specify the exact form of premultiplication There are two ways to do pre-multiplication of the alpha channel into the color channels: on optical values or on electrical values. While pre-multiplication with optical values is arguably more correct, because operations like blending or scaling require pre-multiplied, optical color channels, wayland and compositors by default work with pre-multiplied electrical values. This is most likely a convention that Wayland took from Cairo. This commit makes sure that the expectation of pre-multiplied electrical values is properly documented. Signed-off-by: Sebastian Wick --- protocol/wayland.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index a2a969bf..4e9f7687 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -469,8 +469,8 @@ interface. If the buffer uses a format that has an alpha channel, the alpha channel - is assumed to be premultiplied in the color channels unless otherwise - specified. + is assumed to be premultiplied in the electrical color channel values + (after transfer function encoding) unless otherwise specified. Note, because wl_buffer objects are created from multiple independent factory interfaces, the wl_buffer interface is frozen at version 1. From a3c499493b10a77562f782d9fbf988f1b93eba9b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 9 May 2023 12:04:13 +0200 Subject: [PATCH 0931/1152] protocol: refer to wl_surface.offset in set_cursor The offset in wl_surface.attach has been superseded by wl_surface.offset. Refer to the new request instead of using the deprecated one. Signed-off-by: Simon Ser --- protocol/wayland.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 4e9f7687..2d5cbe45 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2016,9 +2016,9 @@ where (x, y) are the coordinates of the pointer location, in surface-local coordinates. - On surface.attach requests to the pointer surface, hotspot_x + On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters - passed to the request. Attach must be confirmed by + passed to the request. The offset must be applied by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set From 56dfdb7614dd6485e228f662d7d2ae9ce8b68719 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 22 May 2023 20:10:40 +0200 Subject: [PATCH 0932/1152] server: use bool in struct fields Use bool instead of int for boolean values, to make it more explicit what the field contains. For instance "error" is not to be confused with an error code. This is all private API. Signed-off-by: Simon Ser --- src/wayland-server.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 51797bf0..2edf621a 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -83,13 +83,13 @@ struct wl_client { pid_t pid; uid_t uid; gid_t gid; - int error; + bool error; struct wl_priv_signal resource_created_signal; }; struct wl_display { struct wl_event_loop *loop; - int run; + bool run; uint32_t next_global_name; uint32_t serial; @@ -217,7 +217,7 @@ handle_array(struct wl_resource *resource, uint32_t opcode, return; if (!verify_objects(resource, opcode, args)) { - resource->client->error = 1; + resource->client->error = true; return; } @@ -225,14 +225,14 @@ handle_array(struct wl_resource *resource, uint32_t opcode, &object->interface->events[opcode]); if (closure == NULL) { - resource->client->error = 1; + resource->client->error = true; return; } log_closure(resource, closure, true); if (send_func(closure, resource->client->connection)) - resource->client->error = 1; + resource->client->error = true; wl_closure_destroy(closure); } @@ -303,7 +303,7 @@ wl_resource_post_error_vargs(struct wl_resource *resource, wl_resource_post_event(client->display_resource, WL_DISPLAY_ERROR, resource, code, buffer); - client->error = 1; + client->error = true; } @@ -1477,7 +1477,7 @@ wl_display_terminate(struct wl_display *display) int ret; uint64_t terminate = 1; - display->run = 0; + display->run = false; ret = write(display->terminate_efd, &terminate, sizeof(terminate)); assert (ret >= 0 || errno == EAGAIN); @@ -1486,7 +1486,7 @@ wl_display_terminate(struct wl_display *display) WL_EXPORT void wl_display_run(struct wl_display *display) { - display->run = 1; + display->run = true; while (display->run) { wl_display_flush_clients(display); From f181de1bcf7dc34898144498f1323c184e73f79d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 20 Jun 2023 09:13:57 +0200 Subject: [PATCH 0933/1152] tests: add missing proxy-test This was probably lost during a rebase. Signed-off-by: Simon Ser --- tests/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/meson.build b/tests/meson.build index 40e3ab31..6cdd2b4a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -146,6 +146,10 @@ tests = { 'headers-protocol-core-test.c', ], 'os-wrappers-test': [], + 'proxy-test': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], } foreach test_name, test_extra_sources: tests From 4a7348e48c05962c7ca5a92f055622263a40242c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 20 Jun 2023 09:15:02 +0200 Subject: [PATCH 0934/1152] egl: add missing ABI check test We were building the executable for the test, but not declaring the test. Signed-off-by: Simon Ser --- egl/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/egl/meson.build b/egl/meson.build index b3cbdf31..c5123779 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -9,7 +9,8 @@ wayland_egl = library( install: true ) -executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') +wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') +test('wayland-egl abi check', wayland_egl_abi_check) nm_path = find_program('nm').full_path() From 4ec379ebcc4d33b3ffa493df12438ade2610eb5f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 26 Jun 2023 12:34:59 +0200 Subject: [PATCH 0935/1152] tests: manually wrap libc functions The way we're wrapping libc functions via dlsym() is pretty fragile and breaks on FreeBSD. The failures happen in our CI and are pretty random, see e.g. [1]. Use a more manual way to wrap via a function pointer. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/jobs/44204010 Signed-off-by: Simon Ser --- src/wayland-os.c | 24 +++++++----- tests/os-wrappers-test.c | 85 +++++++++++++++------------------------- 2 files changed, 47 insertions(+), 62 deletions(-) diff --git a/src/wayland-os.c b/src/wayland-os.c index a9066cae..a0db2e84 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -42,6 +42,12 @@ #include "wayland-os.h" +/* used by tests */ +int (*wl_fcntl)(int fildes, int cmd, ...) = fcntl; +int (*wl_socket)(int domain, int type, int protocol) = socket; +ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags) = recvmsg; +int (*wl_epoll_create1)(int flags) = epoll_create1; + static int set_cloexec_or_close(int fd) { @@ -50,11 +56,11 @@ set_cloexec_or_close(int fd) if (fd == -1) return -1; - flags = fcntl(fd, F_GETFD); + flags = wl_fcntl(fd, F_GETFD); if (flags == -1) goto err; - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + if (wl_fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) goto err; return fd; @@ -69,13 +75,13 @@ wl_os_socket_cloexec(int domain, int type, int protocol) { int fd; - fd = socket(domain, type | SOCK_CLOEXEC, protocol); + fd = wl_socket(domain, type | SOCK_CLOEXEC, protocol); if (fd >= 0) return fd; if (errno != EINVAL) return -1; - fd = socket(domain, type, protocol); + fd = wl_socket(domain, type, protocol); return set_cloexec_or_close(fd); } @@ -124,13 +130,13 @@ wl_os_dupfd_cloexec(int fd, int minfd) { int newfd; - newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd); + newfd = wl_fcntl(fd, F_DUPFD_CLOEXEC, minfd); if (newfd >= 0) return newfd; if (errno != EINVAL) return -1; - newfd = fcntl(fd, F_DUPFD, minfd); + newfd = wl_fcntl(fd, F_DUPFD, minfd); return set_cloexec_or_close(newfd); } @@ -143,7 +149,7 @@ recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags) int *fd; int *end; - len = recvmsg(sockfd, msg, flags); + len = wl_recvmsg(sockfd, msg, flags); if (len == -1) return -1; @@ -179,7 +185,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) #else ssize_t len; - len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC); + len = wl_recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC); if (len >= 0) return len; if (errno != EINVAL) @@ -194,7 +200,7 @@ wl_os_epoll_create_cloexec(void) int fd; #ifdef EPOLL_CLOEXEC - fd = epoll_create1(EPOLL_CLOEXEC); + fd = wl_epoll_create1(EPOLL_CLOEXEC); if (fd >= 0) return fd; if (errno != EINVAL) diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 8d8c3ab9..23ddced8 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -45,50 +44,20 @@ #include "test-runner.h" #include "wayland-os.h" +extern int (*wl_socket)(int domain, int type, int protocol); +extern int (*wl_fcntl)(int fildes, int cmd, ...); +extern ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags); +extern int (*wl_epoll_create1)(int flags); + static int fall_back; -/* Play nice with sanitizers - * - * Sanitizers need to intercept syscalls in the compiler run-time library. As - * this isn't a separate ELF object, the usual dlsym(RTLD_NEXT) approach won't - * work: there can only be one function named "socket" etc. To support this, the - * sanitizer library names its interceptors with the prefix __interceptor_ ("__" - * being reserved for the implementation) and then weakly aliases it to the real - * function. The functions we define below will override the weak alias, and we - * can call them by the __interceptor_ name directly. This allows the sanitizer - * to do its work before calling the next version of the function via dlsym. - * - * However! We also don't know which of these functions the sanitizer actually - * wants to override, so we have to declare our own weak symbols for - * __interceptor_ and check at run time if they linked to anything or not. -*/ +static int wrapped_calls_socket = 0; +static int wrapped_calls_fcntl = 0; +static int wrapped_calls_recvmsg = 0; +static int wrapped_calls_epoll_create1 = 0; -#define DECL(ret_type, func, ...) \ - ret_type __interceptor_ ## func(__VA_ARGS__) __attribute__((weak)); \ - static ret_type (*real_ ## func)(__VA_ARGS__); \ - static int wrapped_calls_ ## func; - -#define REAL(func) (__interceptor_ ## func) ? \ - __interceptor_ ## func : \ - (__typeof__(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func) - -DECL(int, socket, int, int, int); -DECL(int, fcntl, int, int, ...); -DECL(ssize_t, recvmsg, int, struct msghdr *, int); -DECL(int, epoll_create1, int); - -static void -init_fallbacks(int do_fallbacks) -{ - fall_back = do_fallbacks; - real_socket = REAL(socket); - real_fcntl = REAL(fcntl); - real_recvmsg = REAL(recvmsg); - real_epoll_create1 = REAL(epoll_create1); -} - -__attribute__ ((visibility("default"))) int -socket(int domain, int type, int protocol) +static int +socket_wrapper(int domain, int type, int protocol) { wrapped_calls_socket++; @@ -97,11 +66,11 @@ socket(int domain, int type, int protocol) return -1; } - return real_socket(domain, type, protocol); + return socket(domain, type, protocol); } -__attribute__ ((visibility("default"))) int -(fcntl)(int fd, int cmd, ...) +static int +fcntl_wrapper(int fd, int cmd, ...) { va_list ap; int arg; @@ -131,13 +100,13 @@ __attribute__ ((visibility("default"))) int } if (has_arg) { - return real_fcntl(fd, cmd, arg); + return fcntl(fd, cmd, arg); } - return real_fcntl(fd, cmd); + return fcntl(fd, cmd); } -__attribute__ ((visibility("default"))) ssize_t -recvmsg(int sockfd, struct msghdr *msg, int flags) +static ssize_t +recvmsg_wrapper(int sockfd, struct msghdr *msg, int flags) { wrapped_calls_recvmsg++; @@ -146,11 +115,11 @@ recvmsg(int sockfd, struct msghdr *msg, int flags) return -1; } - return real_recvmsg(sockfd, msg, flags); + return recvmsg(sockfd, msg, flags); } -__attribute__ ((visibility("default"))) int -epoll_create1(int flags) +static int +epoll_create1_wrapper(int flags) { wrapped_calls_epoll_create1++; @@ -160,7 +129,17 @@ epoll_create1(int flags) return -1; } - return real_epoll_create1(flags); + return epoll_create1(flags); +} + +static void +init_fallbacks(int do_fallbacks) +{ + fall_back = do_fallbacks; + wl_fcntl = fcntl_wrapper; + wl_socket = socket_wrapper; + wl_recvmsg = recvmsg_wrapper; + wl_epoll_create1 = epoll_create1_wrapper; } static void From 6d3334657180f3663b8d83636f4d1bc2097492d2 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Wed, 24 May 2023 11:24:23 -0700 Subject: [PATCH 0936/1152] debug: Replace "@" with "#" in logs Wayland debug logs resemble email addresses. This is a problem when anonymizing logs from users. For example: [2512874.343] xdg_surface@700.configure(333) In the above log line, the substring "surface@700.config" can be mistaken for an email address and redacted during anonymization. Signed-off-by: Alex Yang --- src/connection.c | 6 +++--- src/wayland-client.c | 6 +++--- src/wayland-server.c | 8 ++++---- tests/queue-test.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/connection.c b/src/connection.c index ceaeac14..8a2d9e95 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1283,7 +1283,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(f, "[%7u.%03u] %s%s%s@%u.%s(", + fprintf(f, "[%7u.%03u] %s%s%s#%u.%s(", time / 1000, time % 1000, discarded ? "discarded " : "", send ? " -> " : "", @@ -1323,7 +1323,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, break; case 'o': if (closure->args[i].o) - fprintf(f, "%s@%u", + fprintf(f, "%s#%u", closure->args[i].o->interface->name, closure->args[i].o->id); else @@ -1335,7 +1335,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, else nval = closure->args[i].n; - fprintf(f, "new id %s@", + fprintf(f, "new id %s#", (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]"); diff --git a/src/wayland-client.c b/src/wayland-client.c index 105f9bed..607fdb4b 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -312,7 +312,7 @@ wl_event_queue_release(struct wl_event_queue *queue) wl_list_for_each_safe(proxy, tmp, &queue->proxy_list, queue_link) { if (queue != &queue->display->default_queue) { - wl_log(" %s@%u still attached\n", + wl_log(" %s#%u still attached\n", proxy->object.interface->name, proxy->object.id); } @@ -1045,7 +1045,7 @@ display_handle_error(void *data, const struct wl_interface *interface; if (proxy) { - wl_log("%s@%u: error %d: %s\n", + wl_log("%s#%u: error %d: %s\n", proxy->object.interface->name, proxy->object.id, code, message); @@ -1526,7 +1526,7 @@ queue_event(struct wl_display *display, int len) clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(stderr, "[%7u.%03u] discarded [%s]@%d.[event %d]" + fprintf(stderr, "[%7u.%03u] discarded [%s]#%d.[event %d]" "(%d fd, %d byte)\n", time / 1000, time % 1000, zombie ? "zombie" : "unknown", diff --git a/src/wayland-server.c b/src/wayland-server.c index 2edf621a..e784ef6b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -391,7 +391,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) if (opcode >= object->interface->method_count) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, - "invalid method %d, object %s@%u", + "invalid method %d, object %s#%u", opcode, object->interface->name, object->id); @@ -405,7 +405,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, "invalid method %d (since %d < %d)" - ", object %s@%u", + ", object %s#%u", opcode, resource->version, since, object->interface->name, object->id); @@ -423,7 +423,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) wl_closure_lookup_objects(closure, &client->objects) < 0) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, - "invalid arguments for %s@%u.%s", + "invalid arguments for %s#%u.%s", object->interface->name, object->id, message->name); @@ -1343,7 +1343,7 @@ wl_global_remove(struct wl_global *global) if (global->removed) wl_abort("wl_global_remove: called twice on the same " - "global '%s@%"PRIu32"'", global->interface->name, + "global '%s#%"PRIu32"'", global->interface->name, global->name); wl_list_for_each(resource, &display->registry_resource_list, link) diff --git a/tests/queue-test.c b/tests/queue-test.c index 41293100..6562139a 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -383,7 +383,7 @@ client_test_queue_destroy_with_attached_proxies(void) /* Check that the log contains some information about the attached * wl_callback proxy. */ log = map_file(client_log_fd, &log_len); - ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u", + ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u", wl_proxy_get_id((struct wl_proxy *) callback)); assert(ret > 0 && ret < (int)sizeof(callback_name) && "callback name creation failed (possibly truncated)"); @@ -456,7 +456,7 @@ client_test_queue_destroy_default_with_attached_proxies(void) /* Check that the log does not contain any warning about the attached * wl_callback proxy. */ log = maybe_map_file(client_log_fd, &log_len); - ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u", + ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u", wl_proxy_get_id((struct wl_proxy *) callback)); assert(ret > 0 && ret < (int)sizeof(callback_name) && "callback name creation failed (possibly truncated)"); From e3908eb36062883cc56c3f60ebdcaa835ea4298d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 7 Jul 2023 10:44:56 +1000 Subject: [PATCH 0937/1152] Add a triage-policies file for bugbot With a default template for the common case of "this is not a protocol bug". Signed-off-by: Peter Hutterer --- .triage-policies.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .triage-policies.yml diff --git a/.triage-policies.yml b/.triage-policies.yml new file mode 100644 index 00000000..580bead4 --- /dev/null +++ b/.triage-policies.yml @@ -0,0 +1,33 @@ +# This is a set of bugbot commands for issues and merge requests - setting any of the +# bugbot::foo labels will trigger gitlab-triage to run with this ruleset (well, the +# one we have on the main branch at the time) +# +# Note that for adding labels, the label must first created in the project. +resource_rules: + issues: + rules: + - name: "Close bugs that aren't Wayland bugs" + conditions: + labels: + - "bugbot::not-wayland" + actions: + remove_labels: + - "bugbot::not-wayland" + comment: | + Thank you for the report, but your issue does not look like it would belong here. Sorry. + + This repository is for the Wayland protocol specification and the + low-level C library that deals with the protocol. + + This issue here is a bug not with the protocol itself but with either + - your compositor or desktop environment's implementation of the Wayland protocol and surrounding functionality, + - the individual application that triggers this issue, or + - the kernel driver used by your hardware + + Please file the issue against your compositor/desktop environment, the application + or the kernel drivers instead, whichever seems more likely to you. If you are not sure, + file an issue against the application. + status: "close" + merge_requests: + rules: + [] From 72da004b3eed19a94265d564f1fa59276ceb4340 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 22 Jun 2023 11:09:48 +0200 Subject: [PATCH 0938/1152] protocol: fix whitespace This file uses tabs instead of 8 spaces. Signed-off-by: Simon Ser --- protocol/wayland.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 2d5cbe45..5efe562d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -262,11 +262,11 @@ created, but using the new size. This request can only be used to make the pool bigger. - This request only changes the amount of bytes that are mmapped - by the server and does not touch the file corresponding to the - file descriptor passed at creation time. It is the client's - responsibility to ensure that the file is at least as big as - the new pool size. + This request only changes the amount of bytes that are mmapped + by the server and does not touch the file corresponding to the + file descriptor passed at creation time. It is the client's + responsibility to ensure that the file is at least as big as + the new pool size. @@ -1435,7 +1435,7 @@ + summary="surface was destroyed before its role object"/> @@ -1464,9 +1464,9 @@ When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an - 'invalid_offset' error being raised. The x and y arguments are ignored - and do not change the pending state. To achieve equivalent semantics, - use wl_surface.offset. + 'invalid_offset' error being raised. The x and y arguments are ignored + and do not change the pending state. To achieve equivalent semantics, + use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. From 7b27881cd1cbe55ec66c1455867eda9606eab8c7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Aug 2023 16:46:11 +0200 Subject: [PATCH 0939/1152] cursor: check return value of snprintf() Fixes a new warning in GCC 7: FAILED: cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o cc -Icursor/libwayland-cursor.so.0.22.90.p -Icursor -I../cursor -I. -I.. -Isrc -I../src -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c99 -O3 -D_POSIX_C_SOURCE=200809L -Wno-unused-parameter -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden -fPIC '-DICONDIR="/usr/share/X11/icons"' -MD -MQ cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o -MF cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o.d -o cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o -c ../cursor/xcursor.c ../cursor/xcursor.c: In function 'xcursor_load_theme': ../cursor/xcursor.c:596:39: error: '%s' directive output between 7 and 7 bytes may cause result to exceed 'INT_MAX' [-Werror=format-truncation=] 596 | snprintf(full, full_size, "%s/%s/%s", dir, subdir, file); | ^~ ...... 764 | full = xcursor_build_fullname(dir, "cursors", ""); | ~~~~~~~~~ ../cursor/xcursor.c:596:41: error: '/' directive output between 1 and 1 bytes may cause result to exceed 'INT_MAX' [-Werror=format-truncation=] 596 | snprintf(full, full_size, "%s/%s/%s", dir, subdir, file); | ^ cc1: all warnings being treated as errors Signed-off-by: Simon Ser --- cursor/xcursor.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 43a5292c..6766c564 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -585,6 +585,7 @@ xcursor_build_fullname(const char *dir, const char *subdir, const char *file) { char *full; size_t full_size; + int ret; if (!dir || !subdir || !file) return NULL; @@ -593,7 +594,11 @@ xcursor_build_fullname(const char *dir, const char *subdir, const char *file) full = malloc(full_size); if (!full) return NULL; - snprintf(full, full_size, "%s/%s/%s", dir, subdir, file); + ret = snprintf(full, full_size, "%s/%s/%s", dir, subdir, file); + if (ret < 0) { + free(full); + return NULL; + } return full; } From a81f947affe92550b7506b1403f6067b231ff542 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Aug 2023 16:20:13 +0200 Subject: [PATCH 0940/1152] ci: upgrade ci-templates Newer ci-templates contains bugfixes. While at it, stop using a GitLab YAML reference, because we only use this value in one spot. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f7f74ec4..4db42cd7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,15 +37,13 @@ # - documentation at https://freedesktop.pages.freedesktop.org/ci-templates/ # - repo at https://gitlab.freedesktop.org/freedesktop/ci-templates/ -# Here we use a fixed ref in order to isolate ourselves from ci-templates -# API changes. If you need new features from ci-templates you must bump -# this to the current SHA you require from the ci-templates repo, however -# be aware that you may need to account for API changes when doing so. -.templates_sha: &template_sha d5aa3941aa03c2f716595116354fb81eb8012acb # see https://docs.gitlab.com/ee/ci/yaml/#includefile - include: - project: 'freedesktop/ci-templates' - ref: *template_sha + # Here we use a fixed ref in order to isolate ourselves from ci-templates + # API changes. If you need new features from ci-templates you must bump + # this to the current SHA you require from the ci-templates repo, however + # be aware that you may need to account for API changes when doing so. + ref: b791bd48996e3ced9ca13f1c5ee82be8540b8adb file: - '/templates/debian.yml' - '/templates/freebsd.yml' From 63b0050561e9fa396a7b1b445e825b12e0083b40 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Aug 2023 16:22:06 +0200 Subject: [PATCH 0941/1152] ci: upgrade Debian to bookworm This is the current Debian stable release. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4db42cd7..2978ece8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -70,12 +70,12 @@ stages: .os-debian: variables: BUILD_OS: debian - FDO_DISTRIBUTION_VERSION: bullseye + FDO_DISTRIBUTION_VERSION: bookworm FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' - FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.56.0' + FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson==0.56.0' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2022-08-08.0" + FDO_DISTRIBUTION_TAG: "2023-08-02.0" .debian-x86_64: extends: From 379a6f6759bb261d64a5f178e67f0e5f1eabad7a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Aug 2023 16:23:05 +0200 Subject: [PATCH 0942/1152] ci: upgrade FreeBSD to 13.2 Signed-off-by: Simon Ser --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2978ece8..2ac971a1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -299,11 +299,11 @@ armv7-release-debian-build: .os-freebsd: variables: BUILD_OS: freebsd - FDO_DISTRIBUTION_VERSION: "13.1" + FDO_DISTRIBUTION_VERSION: "13.2" FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2022-09-08.0" + FDO_DISTRIBUTION_TAG: "2023-08-02.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. MESON_ARGS: "-Ddocumentation=false" From edb943dc6464697ba13d7df277aef277721764b7 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Wed, 17 May 2023 12:03:32 +0300 Subject: [PATCH 0943/1152] client: Add method to get display for a given proxy This can be useful for additional validation purposes when handling proxies. This is similar to existing server side API wl_global_get_display. Signed-off-by: David Edmundson --- src/wayland-client-core.h | 3 +++ src/wayland-client.c | 14 ++++++++++++++ tests/proxy-test.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index ce91a6f6..af50f1e5 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -219,6 +219,9 @@ wl_proxy_get_tag(struct wl_proxy *proxy); const char * wl_proxy_get_class(struct wl_proxy *proxy); +struct wl_display * +wl_proxy_get_display(struct wl_proxy *proxy); + void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); diff --git a/src/wayland-client.c b/src/wayland-client.c index 607fdb4b..489f0a8d 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2338,6 +2338,20 @@ wl_proxy_get_class(struct wl_proxy *proxy) return proxy->object.interface->name; } +/** Get the display of a proxy object + * + * \param proxy The proxy object + * \return The wl_display the proxy is associated with + * + * \memberof wl_proxy + * \since 1.23 + */ +WL_EXPORT struct wl_display * +wl_proxy_get_display(struct wl_proxy *proxy) +{ + return proxy->display; +} + /** Assign a proxy to an event queue * * \param proxy The proxy object diff --git a/tests/proxy-test.c b/tests/proxy-test.c index c09468d7..2a8f4254 100644 --- a/tests/proxy-test.c +++ b/tests/proxy-test.c @@ -118,6 +118,8 @@ TEST(proxy_tag) wl_proxy_set_tag((struct wl_proxy *) client.callback_b, &tag_b); + assert(wl_proxy_get_display((struct wl_proxy *) client.callback_b) == client.display); + wl_display_flush(client.display); while (server.sync_count < 2) { From 50ea9c5b1c08bac30be365dca05716a97ea65a92 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 7 Nov 2023 22:38:52 -0500 Subject: [PATCH 0944/1152] connection: avoid calling memcpy on NULL, 0 Due to what is arguably a mistake in the C language specification, passing NULL to memcpy and friends is undefined behavior (UB) even when the count is 0. C additionally mistakenly leaves NULL + 0 and NULL - NULL undefined. (C++ fixes this mistake.) These are very problematic because (NULL, 0) is a natural representation of the empty slice. Some details: https://github.com/llvm/llvm-project/issues/49459 https://www.imperialviolet.org/2016/06/26/nonnull.html Unfortunately, despite how clearly this is a mistake, glibc headers and GCC now try to exploit this specification mistake and will miscompile code, so C projects need to workaround this. In particular, UBSan from Clang will flag this as a bug (although Clang itself has the good sense to never lean on this bug). We've run into a few UBSan errors in Chromium stemming from Wayland's memcpy calls. Add runtime guards as needed to avoid these cases. Note: Chromium's copy of wayland has https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/188 applied. It is possible the ring_buffer_copy UB cases are only reachable with that MR applied, I'm not sure. But it seemed simplest to just add the fix to wayland as-is. Then when/if that MR lands, it will pick this up. Signed-off-by: David Benjamin --- src/connection.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index 8a2d9e95..f2e5837f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -83,6 +83,9 @@ ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count) return -1; } + if (count == 0) + return 0; + head = MASK(b->head); if (head + count <= sizeof b->data) { memcpy(b->data + head, data, count); @@ -150,6 +153,9 @@ ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count) { uint32_t tail, size; + if (count == 0) + return; + tail = MASK(b->tail); if (tail + count <= sizeof b->data) { memcpy(data, b->data + tail, count); @@ -1186,7 +1192,8 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, if (p + div_roundup(size, sizeof *p) > end) goto overflow; - memcpy(p, closure->args[i].a->data, size); + if (size != 0) + memcpy(p, closure->args[i].a->data, size); p += div_roundup(size, sizeof *p); break; default: From e4eb42d073056201d4569ddff16743265f1eedf6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 19 Oct 2023 16:29:07 +0200 Subject: [PATCH 0945/1152] protocol: refer to wl_surface.offset in wl_data_device.start_drag Passing an offset to wl_surface.attach is not supported in the latest version of the interface. Signed-off-by: Simon Ser --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 5efe562d..bc7865b0 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -884,7 +884,7 @@ The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor - hotspot, but subsequent wl_surface.attach request can move the + hotspot, but subsequent wl_surface.offset requests can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, From 3007718b0c84407ec0561ddac734a8bcb93dd7fa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 5 Nov 2023 23:05:30 +0100 Subject: [PATCH 0946/1152] gitlab: make issue template the default The issue template is hard to notice because it's not the default. Users have to explicitly select it from the easy-to-miss dropdown to get the warning. Make the template the default one, so that new users are less likely to miss it. Signed-off-by: Simon Ser --- .gitlab/issue_templates/{Bug.md => default.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .gitlab/issue_templates/{Bug.md => default.md} (82%) diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/default.md similarity index 82% rename from .gitlab/issue_templates/Bug.md rename to .gitlab/issue_templates/default.md index b78a6153..f8149cee 100644 --- a/.gitlab/issue_templates/Bug.md +++ b/.gitlab/issue_templates/default.md @@ -4,5 +4,5 @@ library only. Issues with Wayland during day-to-day usage are almost certainly a bug in your compositor and **not** a bug with in this repository. -Please remove this comment before filing your bug. +Please remove this comment before filing your issue. --> From 2a91f01d6c617f8f2bd1c5bf18cfa9bd21a732f6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Oct 2023 18:28:25 +0200 Subject: [PATCH 0947/1152] util: simplify wl_fixed_from_double() Same as 0e0ae7e290f2 ("util: simplify wl_fixed_to_double()"), but for the reverse function. Signed-off-by: Simon Ser --- src/wayland-util.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 272a3c01..1a451e43 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -626,14 +626,7 @@ wl_fixed_to_double(wl_fixed_t f) static inline wl_fixed_t wl_fixed_from_double(double d) { - union { - double d; - int64_t i; - } u; - - u.d = d + (3LL << (51 - 8)); - - return (wl_fixed_t)u.i; + return (wl_fixed_t) (d * 256.0); } /** From 8a19dc19a1eee48cff9fea03dca4952bc2967d46 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 26 Oct 2023 21:01:54 +0400 Subject: [PATCH 0948/1152] protocol: clarify defaults with wl_compositor@v6 This should be sufficient for clients to not decide to fallback to output based logic to determine scaling/transform when compositor doesn't send any of the v6 events. Signed-off-by: Kirill Chibisov --- protocol/wayland.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index bc7865b0..b4141fca 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1826,6 +1826,9 @@ This event indicates the preferred buffer scale for this surface. It is sent whenever the compositor's preference changes. + Before receiving this event the preferred buffer scale for this surface + is 1. + It is intended that scaling aware clients use this event to scale their content and use wl_surface.set_buffer_scale to indicate the scale they have rendered with. This allows clients to supply a higher detail @@ -1839,6 +1842,9 @@ This event indicates the preferred buffer transform for this surface. It is sent whenever the compositor's preference changes. + Before receiving this event the preferred buffer transform for this + surface is normal. + It is intended that transform aware clients use this event to apply the transform to their content and use wl_surface.set_buffer_transform to indicate the transform they have rendered with. From 82d8b21827c4f58013a4061fb3c813d9ae80407e Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Mon, 23 Oct 2023 11:14:02 +0300 Subject: [PATCH 0949/1152] protocol: improve wl_subsurface.{set_position,place_above} description Don't mention when the parent surface state is applied; the parent surface isn't necessarily a sub-surface. Signed-off-by: Kirill Primak --- protocol/wayland.xml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index b4141fca..37a7603b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -3103,9 +3103,7 @@ surface area. Negative values are allowed. The scheduled coordinates will take effect whenever the state of the - parent surface is applied. When this happens depends on whether the - parent surface is in synchronized mode or not. See - wl_subsurface.set_sync and wl_subsurface.set_desync for details. + parent surface is applied. If more than one set_position request is invoked by the client before the commit of the parent surface, the position of a new request always @@ -3128,9 +3126,7 @@ The z-order is double-buffered. Requests are handled in order and applied immediately to a pending state. The final pending state is copied to the active state the next time the state of the parent - surface is applied. When this happens depends on whether the parent - surface is in synchronized mode or not. See wl_subsurface.set_sync and - wl_subsurface.set_desync for details. + surface is applied. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. From 86588fbdebe7f6ac9363d98f524e4ae14bd4b019 Mon Sep 17 00:00:00 2001 From: Francesco Guastella Date: Thu, 7 Sep 2023 08:20:20 +0200 Subject: [PATCH 0950/1152] build: define tests in egl/meson.build when the 'tests' option is enabled Signed-off-by: Francesco Guastella --- egl/meson.build | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/egl/meson.build b/egl/meson.build index c5123779..76c6ee21 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -9,19 +9,21 @@ wayland_egl = library( install: true ) -wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') -test('wayland-egl abi check', wayland_egl_abi_check) +if get_option('tests') + wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') + test('wayland-egl abi check', wayland_egl_abi_check) -nm_path = find_program('nm').full_path() + nm_path = find_program('nm').full_path() -test( - 'wayland-egl symbols check', - find_program('wayland-egl-symbols-check'), - env: [ - 'WAYLAND_EGL_LIB=@0@'.format(wayland_egl.full_path()), - 'NM=@0@'.format(nm_path) - ] -) + test( + 'wayland-egl symbols check', + find_program('wayland-egl-symbols-check'), + env: [ + 'WAYLAND_EGL_LIB=@0@'.format(wayland_egl.full_path()), + 'NM=@0@'.format(nm_path) + ] + ) +endif install_headers([ 'wayland-egl.h', From 6626d4d98c192130681543d59ff5e0e7bac9ab4a Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 5 May 2022 14:11:23 +0200 Subject: [PATCH 0951/1152] protocol: wl_subsurface will never be focused The spec does not describe which actions cause the compositor to assign keyboard focus to a surface, leaving this up to the compositor. Compositors differ in their behavior when the user clicks on a sub-surface. Some will move the keyboard focus to the subsurface whereas others will only ever assign the keyboard focus to toplevel surfaces. Some applications (e.g. firefox) seem to require the second behavior. This patch specifies that sub-surfaces never get the keyboard focus. Signed-off-by: Julian Orth --- protocol/wayland.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 37a7603b..5c2a8030 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -3078,6 +3078,8 @@ If the parent wl_surface object is destroyed, the sub-surface is unmapped. + + A sub-surface never has the keyboard focus of any seat. From 0e139cfbc710156bc4b4b3c254c7b2ff2f10ff34 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 15 Jan 2024 14:29:10 +0100 Subject: [PATCH 0952/1152] build: add a gen-scanner-test target This adds a command to re-generate the test data. This needs to be done when either an XML source file or the scanner's output is changed. Signed-off-by: Simon Ser --- tests/data/README.md | 3 +++ tests/meson.build | 20 ++++++++++++++------ tests/scanner-test-gen.sh | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 tests/data/README.md create mode 100755 tests/scanner-test-gen.sh diff --git a/tests/data/README.md b/tests/data/README.md new file mode 100644 index 00000000..14813453 --- /dev/null +++ b/tests/data/README.md @@ -0,0 +1,3 @@ +To re-generate the test data, run: + + ninja -C build/ gen-scanner-test diff --git a/tests/meson.build b/tests/meson.build index 6cdd2b4a..236f08c0 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -75,15 +75,23 @@ endif sed_path = find_program('sed').full_path() if get_option('scanner') + scanner_test_env = [ + 'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()), + 'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()), + 'SED=@0@'.format(sed_path), + 'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()), + ] + test( 'scanner-test', find_program('scanner-test.sh'), - env: [ - 'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()), - 'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()), - 'SED=@0@'.format(sed_path), - 'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()), - ], + env: scanner_test_env, + ) + + run_target( + 'gen-scanner-test', + command: find_program('scanner-test-gen.sh'), + env: scanner_test_env, ) endif diff --git a/tests/scanner-test-gen.sh b/tests/scanner-test-gen.sh new file mode 100755 index 00000000..5af1a727 --- /dev/null +++ b/tests/scanner-test-gen.sh @@ -0,0 +1,21 @@ +#!/bin/sh -eu + +generate() { + "$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_DATA_DIR/$3" + "$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \ + "$TEST_DATA_DIR/$3" +} + +generate "code" "example.xml" "example-code.c" +generate "client-header" "example.xml" "example-client.h" +generate "server-header" "example.xml" "example-server.h" + +generate "code" "small.xml" "small-code.c" +generate "client-header" "small.xml" "small-client.h" +generate "server-header" "small.xml" "small-server.h" + +generate "-c code" "small.xml" "small-code-core.c" +generate "-c client-header" "small.xml" "small-client-core.h" +generate "-c server-header" "small.xml" "small-server-core.h" + +generate "private-code" "small.xml" "small-private-code.c" From 6daa1b8713f0fa569eb9f5c101b61c4ef1500775 Mon Sep 17 00:00:00 2001 From: Consolatis Date: Wed, 1 Feb 2023 14:35:15 +0100 Subject: [PATCH 0953/1152] cursor: add aliases for cursor name spec The cursor name spec [1] describes how cursors should be named, and is widely used. Add aliases so that users can pass these names to libwayland-cursor without having to add fallbacks for X11 cursor names. [1]: https://www.freedesktop.org/wiki/Specifications/cursor-spec/ Signed-off-by: Simon Ser --- cursor/cursor-data.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cursor/cursor-data.h b/cursor/cursor-data.h index dd7a80af..2ee2f8a7 100644 --- a/cursor/cursor-data.h +++ b/cursor/cursor-data.h @@ -551,4 +551,19 @@ static struct cursor_metadata { { "xterm", 9, 16, 4, 8, 2400 }, { "hand1", 13, 16, 12, 0, 2544 }, { "watch", 16, 16, 15, 9, 2752 }, + + /* https://www.freedesktop.org/wiki/Specifications/cursor-spec/ */ + { "sw-resize", 16, 16, 1, 14, 0 }, + { "se-resize", 16, 16, 14, 14, 256 }, + { "s-resize", 15, 16, 7, 14, 512 }, + { "all-scroll", 16, 16, 8, 8, 752 }, + { "default", 10, 16, 1, 1, 1008 }, + { "w-resize", 16, 15, 1, 7, 1168 }, + { "e-resize", 16, 15, 14, 7, 1408 }, + { "nw-resize", 16, 16, 1, 1, 1648 }, + { "ne-resize", 16, 16, 14, 1, 1904 }, + { "n-resize", 15, 16, 7, 1, 2160 }, + { "text", 9, 16, 4, 8, 2400 }, + { "pointer", 13, 16, 12, 0, 2544 }, + { "wait", 16, 16, 15, 9, 2752 }, }; From dc1da181db066415edfb73f4d9a579bc7b72b223 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 19 Oct 2023 16:31:52 +0200 Subject: [PATCH 0954/1152] protocol: document wl_surface.offset for sub-surfaces Document that the request is ignored, since this is the behavior of most compositors. Signed-off-by: Simon Ser --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 5c2a8030..5731d69e 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -3080,6 +3080,9 @@ unmapped. A sub-surface never has the keyboard focus of any seat. + + The wl_surface.offset request is ignored: clients must use set_position + instead to move the sub-surface. From 56b9c92b9881527d05ea9caa34c2c87e5927aa71 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 25 Jul 2023 21:48:27 +0200 Subject: [PATCH 0955/1152] util: use C23 typeof if available Instead of using the non-standard __typeof__, prefer the standard typeof operator introduced in C23. Signed-off-by: Simon Ser --- src/wayland-util.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 1a451e43..79aabc7b 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -68,6 +68,12 @@ extern "C" { #define WL_PRINTF(x, y) #endif +#if __STDC_VERSION__ >= 202311L +#define WL_TYPEOF(expr) typeof(expr) +#else +#define WL_TYPEOF(expr) __typeof__(expr) +#endif + /** \class wl_object * * \brief A protocol object. @@ -406,8 +412,8 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other); * \return The container for the specified pointer */ #define wl_container_of(ptr, sample, member) \ - (__typeof__(sample))((char *)(ptr) - \ - offsetof(__typeof__(*sample), member)) + (WL_TYPEOF(sample))((char *)(ptr) - \ + offsetof(WL_TYPEOF(*sample), member)) /** * Iterates over a list. From 647398ead44ed12556ac61d61e8ae6d9012a18e2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 25 Jul 2023 21:54:49 +0200 Subject: [PATCH 0956/1152] util: use C23 deprecated attribute Signed-off-by: Simon Ser --- src/wayland-util.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 79aabc7b..c99069cc 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -48,7 +48,9 @@ extern "C" { #endif /** Deprecated attribute */ -#if defined(__GNUC__) && __GNUC__ >= 4 +#if __STDC_VERSION__ >= 202311L +#define WL_DEPRECATED [[deprecated]] +#elif defined(__GNUC__) && __GNUC__ >= 4 #define WL_DEPRECATED __attribute__ ((deprecated)) #else #define WL_DEPRECATED From 8072ab0a505d8aeb7b34d3ecd297ca501979d905 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 2 Jan 2024 15:56:25 -0800 Subject: [PATCH 0957/1152] protocol: clarify scale expecations Since the positivity of zero is debatable, and, in some cases scale was simply underspecified, clarify the situation. Signed-off-by: Ben Widawsky --- protocol/wayland.xml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 5731d69e..1d471c53 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1749,11 +1749,11 @@ a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. - If scale is not positive the invalid_scale protocol error is + If scale is not greater than 0 the invalid_scale protocol error is raised. + summary="scale for interpreting buffer contents"/> @@ -1833,6 +1833,8 @@ content and use wl_surface.set_buffer_scale to indicate the scale they have rendered with. This allows clients to supply a higher detail buffer. + + The compositor shall emit a scale value greater than 0. @@ -2838,8 +2840,9 @@ This event contains scaling geometry information that is not in the geometry event. It may be sent after binding the output object or if the output scale changes - later. If it is not sent, the client should assume a - scale of 1. + later. The compositor will emit a non-zero, positive + value for scale. If it is not sent, the client should + assume a scale of 1. A scale larger than 1 means that the compositor will automatically scale surface buffers by this amount From 9e233e31a21b0f58639c261d4dd4d72caa0bbd66 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Nov 2023 16:57:31 +0100 Subject: [PATCH 0958/1152] shm: fix resource versions This was hardcoded to 1 regardless of the version passed to the callback or the version of the parent resource. Signed-off-by: Simon Ser --- src/wayland-shm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 8fb657aa..19386448 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -310,6 +310,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, int seals; int prot; int flags; + uint32_t version; if (size <= 0) { wl_resource_post_error(resource, @@ -358,8 +359,10 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, #else close(fd); #endif + + version = wl_resource_get_version(resource); pool->resource = - wl_resource_create(client, &wl_shm_pool_interface, 1, id); + wl_resource_create(client, &wl_shm_pool_interface, version, id); if (!pool->resource) { wl_client_post_no_memory(client); munmap(pool->data, pool->size); @@ -392,7 +395,7 @@ bind_shm(struct wl_client *client, struct wl_array *additional_formats; uint32_t *p; - resource = wl_resource_create(client, &wl_shm_interface, 1, id); + resource = wl_resource_create(client, &wl_shm_interface, version, id); if (!resource) { wl_client_post_no_memory(client); return; From f06736a8a0880ab159d946b06407268ddb41bd4d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Nov 2023 16:59:11 +0100 Subject: [PATCH 0959/1152] protocol: add wl_shm.release request Allows clients to cleanly release wl_shm objects. Useful for clients using multiple wl_registry objects (e.g. via libraries). Signed-off-by: Simon Ser --- protocol/wayland.xml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 1d471c53..59bedaa4 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -212,7 +212,7 @@ - + The wl_shm_pool object encapsulates a piece of memory shared between the compositor and client. Through the wl_shm_pool @@ -272,7 +272,7 @@ - + A singleton global object that provides support for shared memory. @@ -457,6 +457,17 @@ + + + + + + Using this request a client can tell the server that it is not going to + use the shm object anymore. + + Objects created via this interface remain unaffected. + + From fd42f70bafa26fcf6f39f034b581b35838be71aa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Nov 2023 16:59:20 +0100 Subject: [PATCH 0960/1152] shm: implement version 2 This version adds a release request. Signed-off-by: Simon Ser --- src/wayland-shm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 19386448..0a11736a 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -382,8 +382,15 @@ err_close: close(fd); } +static void +shm_release(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + static const struct wl_shm_interface shm_interface = { - shm_create_pool + shm_create_pool, + shm_release, }; static void @@ -414,7 +421,7 @@ bind_shm(struct wl_client *client, WL_EXPORT int wl_display_init_shm(struct wl_display *display) { - if (!wl_global_create(display, &wl_shm_interface, 1, NULL, bind_shm)) + if (!wl_global_create(display, &wl_shm_interface, 2, NULL, bind_shm)) return -1; return 0; From 8c49ee311245cbe615061e5a20a5e11648be324f Mon Sep 17 00:00:00 2001 From: Andreas Cord-Landwehr Date: Sat, 24 Sep 2022 16:47:46 +0200 Subject: [PATCH 0961/1152] Consider pkgconfig sysroot for pkgdatadir For libs/cflags this is done automatically, but not for manually accessed variables. This matches what wayland-protocols does. Signed-off-by: Andreas Cord-Landwehr --- src/meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/meson.build b/src/meson.build index 9e61f3d4..5d04334e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -65,7 +65,7 @@ if get_option('scanner') version: meson.project_version(), variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), - 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()), + 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()), 'bindir=' + join_paths('${prefix}', get_option('bindir')), 'wayland_scanner=${bindir}/wayland-scanner' ], @@ -214,7 +214,7 @@ if get_option('libraries') filebase: 'wayland-server', variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), - 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()) + 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()) ] ) @@ -253,7 +253,7 @@ if get_option('libraries') filebase: 'wayland-client', variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), - 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()) + 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()) ] ) From 9867bdb111f827e8e6f43e1c1111bb513811f3f1 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Mon, 28 Feb 2022 08:54:47 -0500 Subject: [PATCH 0962/1152] connection: Small simplification to wl_connection_write() wl_connection_write() contained an exact copy of the logic in wl_connection_queue(). Simplify things by just calling wl_connection_queue() from wl_connection_write(). Signed-off-by: John Lindgren --- src/connection.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/connection.c b/src/connection.c index f2e5837f..bcee87e2 100644 --- a/src/connection.c +++ b/src/connection.c @@ -382,14 +382,7 @@ int wl_connection_write(struct wl_connection *connection, const void *data, size_t count) { - if (connection->out.head - connection->out.tail + - count > ARRAY_LENGTH(connection->out.data)) { - connection->want_flush = 1; - if (wl_connection_flush(connection) < 0) - return -1; - } - - if (ring_buffer_put(&connection->out, data, count) < 0) + if (wl_connection_queue(connection, data, count) < 0) return -1; connection->want_flush = 1; From 2f17d480e848dc8cbd047fab9f322f326da54df9 Mon Sep 17 00:00:00 2001 From: Erik Chen Date: Thu, 29 Sep 2022 23:39:40 +0000 Subject: [PATCH 0963/1152] connection: Spruce up logging for client errors. Some code paths that lead to a client error and connection termination have no associated logging, or insufficient logging. This makes it difficult to understand what went wrong. This commit adds or supplements logging for all these code paths. Signed-off-by: Erik Chen --- src/connection.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/connection.c b/src/connection.c index bcee87e2..a6ad4105 100644 --- a/src/connection.c +++ b/src/connection.c @@ -558,20 +558,27 @@ wl_closure_init(const struct wl_message *message, uint32_t size, count = arg_count_for_signature(message->signature); if (count > WL_CLOSURE_MAX_ARGS) { - wl_log("too many args (%d)\n", count); + wl_log("too many args (%d) for %s (signature %s)\n", count, + message->name, message->signature); errno = EINVAL; return NULL; } + int size_to_allocate; + if (size) { *num_arrays = wl_message_count_arrays(message); - closure = zalloc(sizeof *closure + size + - *num_arrays * sizeof(struct wl_array)); + size_to_allocate = sizeof *closure + size + + *num_arrays * sizeof(struct wl_array); } else { - closure = zalloc(sizeof *closure); + size_to_allocate = sizeof *closure; } + closure = zalloc(size_to_allocate); if (!closure) { + wl_log("could not allocate closure of size (%d) for " + "%s (signature %s)\n", size_to_allocate, message->name, + message->signature); errno = ENOMEM; return NULL; } @@ -1202,6 +1209,8 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, return size; overflow: + wl_log("serialize_closure overflow for %s (signature %s)\n", + message->name, message->signature); errno = ERANGE; return -1; } @@ -1219,8 +1228,13 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) buffer_size = buffer_size_for_closure(closure); buffer = zalloc(buffer_size * sizeof buffer[0]); - if (buffer == NULL) + if (buffer == NULL) { + wl_log("wl_closure_send error: buffer allocation failure of " + "size %d\n for %s (signature %s)", + buffer_size * sizeof buffer[0], closure->message->name, + closure->message->signature); return -1; + } size = serialize_closure(closure, buffer, buffer_size); if (size < 0) { @@ -1247,8 +1261,13 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) buffer_size = buffer_size_for_closure(closure); buffer = malloc(buffer_size * sizeof buffer[0]); - if (buffer == NULL) + if (buffer == NULL) { + wl_log("wl_closure_queue error: buffer allocation failure of " + "size %d\n for %s (signature %s)", + buffer_size * sizeof buffer[0], closure->message->name, + closure->message->signature); return -1; + } size = serialize_closure(closure, buffer, buffer_size); if (size < 0) { From b42218f790033c496c48c7d5ba1f8421db794d0b Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 10 Nov 2023 14:21:48 -0600 Subject: [PATCH 0964/1152] client: Allow setting names for queues Allow setting a name for an event queue. The queue is used only for printing additional debug information. Debug output can now show the name of the event queue an event is dispatched from, or the event queue of a proxy when a request is made. Signed-off-by: Derek Foreman --- src/connection.c | 11 +++- src/wayland-client-core.h | 10 ++++ src/wayland-client.c | 96 ++++++++++++++++++++++++++++---- src/wayland-private.h | 3 +- src/wayland-server.c | 2 +- tests/queue-test.c | 112 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 218 insertions(+), 16 deletions(-) diff --git a/src/connection.c b/src/connection.c index a6ad4105..b89166fb 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1283,7 +1283,8 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) void wl_closure_print(struct wl_closure *closure, struct wl_object *target, - int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg)) + int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), + const char *queue_name) { int i; struct argument_details arg; @@ -1302,8 +1303,12 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(f, "[%7u.%03u] %s%s%s#%u.%s(", - time / 1000, time % 1000, + fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000); + + if (queue_name) + fprintf(f, "{%s} ", queue_name); + + fprintf(f, "%s%s%s#%u.%s(", discarded ? "discarded " : "", send ? " -> " : "", target->interface->name, target->id, diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index af50f1e5..20b2a3b2 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -225,6 +225,12 @@ wl_proxy_get_display(struct wl_proxy *proxy); void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); +struct wl_event_queue * +wl_proxy_get_queue(const struct wl_proxy *proxy); + +const char * +wl_event_queue_get_name(const struct wl_event_queue *queue); + struct wl_display * wl_display_connect(const char *name); @@ -272,6 +278,10 @@ wl_display_roundtrip(struct wl_display *display); struct wl_event_queue * wl_display_create_queue(struct wl_display *display); +struct wl_event_queue * +wl_display_create_queue_with_name(struct wl_display *display, + const char *name); + int wl_display_prepare_read_queue(struct wl_display *display, struct wl_event_queue *queue); diff --git a/src/wayland-client.c b/src/wayland-client.c index 489f0a8d..94438e30 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -77,6 +77,7 @@ struct wl_event_queue { struct wl_list event_list; struct wl_list proxy_list; /**< struct wl_proxy::queue_link */ struct wl_display *display; + char *name; }; struct wl_display { @@ -220,11 +221,15 @@ display_protocol_error(struct wl_display *display, uint32_t code, } static void -wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) +wl_event_queue_init(struct wl_event_queue *queue, + struct wl_display *display, + const char *name) { wl_list_init(&queue->event_list); wl_list_init(&queue->proxy_list); queue->display = display; + if (name) + queue->name = strdup(name); } static void @@ -305,8 +310,15 @@ wl_event_queue_release(struct wl_event_queue *queue) struct wl_proxy *proxy, *tmp; if (queue != &queue->display->default_queue) { - wl_log("warning: queue %p destroyed while proxies " - "still attached:\n", queue); + if (queue->name) { + wl_log("warning: queue \"%s\" " + "%p destroyed while proxies " + "still attached:\n", queue->name, queue); + } else { + wl_log("warning: queue " + "%p destroyed while proxies " + "still attached:\n", queue); + } } wl_list_for_each_safe(proxy, tmp, &queue->proxy_list, @@ -350,6 +362,7 @@ wl_event_queue_destroy(struct wl_event_queue *queue) pthread_mutex_lock(&display->mutex); wl_event_queue_release(queue); + free(queue->name); free(queue); pthread_mutex_unlock(&display->mutex); } @@ -371,7 +384,30 @@ wl_display_create_queue(struct wl_display *display) if (queue == NULL) return NULL; - wl_event_queue_init(queue, display); + wl_event_queue_init(queue, display, NULL); + + return queue; +} + +/** Create a new event queue for this display and give it a name + * + * \param display The display context object + * \param name A human readable queue name + * \return A new event queue associated with this display or NULL on + * failure. + * + * \memberof wl_display + */ +WL_EXPORT struct wl_event_queue * +wl_display_create_queue_with_name(struct wl_display *display, const char *name) +{ + struct wl_event_queue *queue; + + queue = zalloc(sizeof *queue); + if (queue == NULL) + return NULL; + + wl_event_queue_init(queue, display, name); return queue; } @@ -885,8 +921,13 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, goto err_unlock; } - if (debug_client) - wl_closure_print(closure, &proxy->object, true, false, NULL); + if (debug_client) { + struct wl_event_queue *queue; + + queue = wl_proxy_get_queue(proxy); + wl_closure_print(closure, &proxy->object, true, false, NULL, + wl_event_queue_get_name(queue)); + } if (wl_closure_send(closure, proxy->display->connection)) { wl_log("Error sending request: %s\n", strerror(errno)); @@ -1188,8 +1229,8 @@ wl_display_connect_to_fd(int fd) display->fd = fd; wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE); - wl_event_queue_init(&display->default_queue, display); - wl_event_queue_init(&display->display_queue, display); + wl_event_queue_init(&display->default_queue, display, "Default Queue"); + wl_event_queue_init(&display->display_queue, display, "Display Queue"); pthread_mutex_init(&display->mutex, NULL); pthread_cond_init(&display->reader_cond, NULL); display->reader_count = 0; @@ -1321,7 +1362,9 @@ wl_display_disconnect(struct wl_display *display) wl_map_for_each(&display->objects, free_zombies, NULL); wl_map_release(&display->objects); wl_event_queue_release(&display->default_queue); + free(display->default_queue.name); wl_event_queue_release(&display->display_queue); + free(display->display_queue.name); pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); close(display->fd); @@ -1611,7 +1654,8 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); if (proxy_destroyed) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, true, id_from_object); + wl_closure_print(closure, &proxy->object, false, true, + id_from_object, queue->name); destroy_queued_closure(closure); return; } @@ -1620,13 +1664,15 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) if (proxy->dispatcher) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, false, id_from_object); + wl_closure_print(closure, &proxy->object, false, false, + id_from_object, queue->name); wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, false, id_from_object); + wl_closure_print(closure, &proxy->object, false, false, + id_from_object, queue->name); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); @@ -2399,6 +2445,34 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) pthread_mutex_unlock(&proxy->display->mutex); } +/** Get a proxy's event queue + * + * \param proxy The proxy to query + * + * Return the event queue + */ +WL_EXPORT struct wl_event_queue * +wl_proxy_get_queue(const struct wl_proxy *proxy) +{ + return proxy->queue; + +} +/** Get the name of an event queue + * + * \param queue The queue to query + * + * Return the human readable name for the event queue + * + * This may be NULL if no name has been set. + * + * \memberof wl_proxy + */ +WL_EXPORT const char * +wl_event_queue_get_name(const struct wl_event_queue *queue) +{ + return queue->name; +} + /** Create a proxy wrapper for making queue assignments thread-safe * * \param proxy The proxy object to be wrapped diff --git a/src/wayland-private.h b/src/wayland-private.h index 9274f1b8..6b506584 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -213,7 +213,8 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, - uint32_t (*n_parse)(union wl_argument *arg)); + uint32_t (*n_parse)(union wl_argument *arg), + const char *queue_name); void wl_closure_destroy(struct wl_closure *closure); diff --git a/src/wayland-server.c b/src/wayland-server.c index e784ef6b..1534114b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -157,7 +157,7 @@ log_closure(struct wl_resource *resource, struct wl_protocol_logger_message message; if (debug_server) - wl_closure_print(closure, object, send, false, NULL); + wl_closure_print(closure, object, send, false, NULL, NULL); if (!wl_list_empty(&display->protocol_loggers)) { message.resource = resource; diff --git a/tests/queue-test.c b/tests/queue-test.c index 6562139a..cb61a85b 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -471,6 +471,106 @@ client_test_queue_destroy_default_with_attached_proxies(void) free(callback); } +static void +check_queue_name(struct wl_proxy *proxy, const char *name) +{ + struct wl_event_queue *queue; + const char *queue_name; + + queue = wl_proxy_get_queue(proxy); + queue_name = wl_event_queue_get_name(queue); + if (!name) + assert(!queue_name); + else + assert(strcmp(queue_name, name) == 0); +} + +static struct wl_callback * +roundtrip_named_queue_nonblock(struct wl_display *display, + struct wl_event_queue *queue, + const char *name) +{ + struct wl_callback *callback; + struct wl_display *wrapped_display = NULL; + + if (queue) { + wrapped_display = wl_proxy_create_wrapper(display); + assert(wrapped_display); + wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue); + check_queue_name((struct wl_proxy *) wrapped_display, name); + + callback = wl_display_sync(wrapped_display); + } else + callback = wl_display_sync(display); + + check_queue_name((struct wl_proxy *) callback, name); + + if (wrapped_display) + wl_proxy_wrapper_destroy(wrapped_display); + + assert(callback != NULL); + + return callback; +} + +static void +client_test_queue_names(void) +{ + struct wl_event_queue *queue1, *queue2, *queue3; + struct wl_display *display; + struct wl_callback *callback1, *callback2, *callback3, *callback4; + struct wl_event_queue *default_queue; + char *log; + size_t log_len; + const char *default_queue_name; + + display = wl_display_connect(NULL); + assert(display); + + default_queue = wl_proxy_get_queue((struct wl_proxy *) display); + default_queue_name = wl_event_queue_get_name(default_queue); + assert(strcmp(default_queue_name, "Default Queue") == 0); + + /* Create some event queues both with and without names. */ + queue1 = wl_display_create_queue_with_name(display, "First"); + assert(queue1); + + queue2 = wl_display_create_queue_with_name(display, "Second"); + assert(queue2); + + queue3 = wl_display_create_queue(display); + assert(queue3); + + /* Create some requests and ensure their queues have the expected + * names. + */ + callback1 = roundtrip_named_queue_nonblock(display, queue1, "First"); + callback2 = roundtrip_named_queue_nonblock(display, queue2, "Second"); + callback3 = roundtrip_named_queue_nonblock(display, queue3, NULL); + callback4 = roundtrip_named_queue_nonblock(display, NULL, "Default Queue"); + + /* Destroy one queue with proxies still attached so we can verify + * that the queue name is in the log message. */ + wl_event_queue_destroy(queue2); + log = map_file(client_log_fd, &log_len); + assert(strstr(log, "Second")); + + /* There's no reason for the First queue name to be present. */ + assert(!strstr(log, "First")); + + munmap(log, log_len); + + wl_callback_destroy(callback1); + wl_callback_destroy(callback2); + wl_callback_destroy(callback3); + wl_callback_destroy(callback4); + + wl_event_queue_destroy(queue1); + wl_event_queue_destroy(queue3); + + wl_display_disconnect(display); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -597,3 +697,15 @@ TEST(queue_destroy_default_with_attached_proxies) display_destroy(d); } + +TEST(queue_names) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_names); + display_run(d); + + display_destroy(d); +} From 88ece8a44d13eb6c00bb1c7c3c7c5a8fce2c3f4b Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Sat, 22 Apr 2023 11:46:19 +0200 Subject: [PATCH 0965/1152] doc: Improve wording for packed IDs "is incompatible with the implementation in libwayland" is a common source of confusion as evidenced by repeated discussions in IRC channel. Improve the wording by making clear that - packing IDs is a protocol requirement - there are implementations (including libwayland) that enforce it Signed-off-by: Mikhail Gusarov --- doc/publican/sources/Protocol.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 57d88357..89d76d8e 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -312,9 +312,10 @@ reserved to represent a null or non-existent object. For efficiency purposes, the IDs are densely packed in the sense that - the ID N will not be used until N-1 has been used. Any ID allocation - algorithm that does not maintain this property is incompatible with - the implementation in libwayland. + the ID N will not be used until N-1 has been used. This ordering is + not merely a guideline, but a strict requirement, and there are + implementations of the protocol that rigorously enforce this rule, + including the ubiquitous libwayland.
From 8f499bf4045f88f3a4b4b0a445befca467bebe20 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 19 Jan 2024 13:34:37 +0300 Subject: [PATCH 0966/1152] protocol: clarify pending wl_buffer destruction This matches the current behavior of KWin, Mutter, and Weston. References: https://gitlab.freedesktop.org/wayland/wayland/-/issues/387 Signed-off-by: Kirill Primak --- protocol/wayland.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 59bedaa4..93f9d553 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1512,8 +1512,9 @@ mutates the underlying buffer storage, the surface contents become undefined immediately. - If wl_surface.attach is sent with a NULL wl_buffer, the - following wl_surface.commit will remove the surface content. + If wl_surface.attach is sent with a NULL wl_buffer, or the pending + wl_buffer has been destroyed, the following wl_surface.commit will + remove the surface content. From d275bc7f84f1cffb62cfb31f55f00dc2c5968cc9 Mon Sep 17 00:00:00 2001 From: Thomas Lukaszewicz Date: Mon, 8 Jan 2024 00:36:10 +0000 Subject: [PATCH 0967/1152] Mitigate UAF crashes due to iteration over freed wl_resources Currently it is possible to iterate over client-owned resources during client destruction that have had their associated memory released. This can occur when client code calls wl_client_destroy(). The following sequence illustrates how this may occur. 1. The server initiates destruction of the connected client via call to wl_client_destroy(). 2. Resource destroy listeners / destructors are invoked and resource memory is freed one resource at a time [1]. 3. If a listener / destructor for a resource results in a call to wl_client_for_each_resource(), the iteration will proceed over resources that have been previously freed in step 2, resulting in UAFs / crashes. The issue is that resources remain in the client's object map even after they have had their memory freed, and are removed from the map only after each individual resource has had its memory released. This patch corrects this by ensuring resource destruction first invokes listeners / destructors and then removing them from the client's object map before releasing the associated memory. [1] https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/src/wayland-server.c?ref_type=heads#L928 Signed-off-by: Thomas Lukaszewicz thomaslukaszewicz@gmail.com --- src/wayland-server.c | 47 ++++++++++++++++++++-------------- tests/resources-test.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 19 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 1534114b..9fd12273 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -717,10 +717,23 @@ resource_is_deprecated(struct wl_resource *resource) return false; } +/** Removes the wl_resource from the client's object map and deletes it. + * + * Triggers the destroy signal and destructor for the resource before + * removing it from the client's object map and releasing the resource's + * memory. + * + * This order is important to ensure listeners and destruction code can + * find the resource before it has been destroyed whilst ensuring the + * resource is not accessible via the object map after memory has been + * freed. + */ static enum wl_iterator_result -destroy_resource(void *element, void *data, uint32_t flags) +remove_and_destroy_resource(void *element, void *data, uint32_t flags) { struct wl_resource *resource = element; + struct wl_client *client = resource->client; + uint32_t id = resource->object.id;; wl_signal_emit(&resource->deprecated_destroy_signal, resource); /* Don't emit the new signal for deprecated resources, as that would @@ -731,6 +744,17 @@ destroy_resource(void *element, void *data, uint32_t flags) if (resource->destroy) resource->destroy(resource); + /* The resource should be cleared from the map before memory is freed. */ + if (id < WL_SERVER_ID_START) { + if (client->display_resource) { + wl_resource_queue_event(client->display_resource, + WL_DISPLAY_DELETE_ID, id); + } + wl_map_insert_at(&client->objects, 0, id, NULL); + } else { + wl_map_remove(&client->objects, id); + } + if (!(flags & WL_MAP_ENTRY_LEGACY)) free(resource); @@ -741,22 +765,9 @@ WL_EXPORT void wl_resource_destroy(struct wl_resource *resource) { struct wl_client *client = resource->client; - uint32_t id; - uint32_t flags; + uint32_t flags = wl_map_lookup_flags(&client->objects, resource->object.id); - id = resource->object.id; - flags = wl_map_lookup_flags(&client->objects, id); - destroy_resource(resource, NULL, flags); - - if (id < WL_SERVER_ID_START) { - if (client->display_resource) { - wl_resource_queue_event(client->display_resource, - WL_DISPLAY_DELETE_ID, id); - } - wl_map_insert_at(&client->objects, 0, id, NULL); - } else { - wl_map_remove(&client->objects, id); - } + remove_and_destroy_resource(resource, NULL, flags); } WL_EXPORT uint32_t @@ -920,12 +931,10 @@ wl_client_get_destroy_late_listener(struct wl_client *client, WL_EXPORT void wl_client_destroy(struct wl_client *client) { - uint32_t serial = 0; - wl_priv_signal_final_emit(&client->destroy_signal, client); wl_client_flush(client); - wl_map_for_each(&client->objects, destroy_resource, &serial); + wl_map_for_each(&client->objects, remove_and_destroy_resource, NULL); wl_map_release(&client->objects); wl_event_source_remove(client->source); close(wl_connection_destroy(client->connection)); diff --git a/tests/resources-test.c b/tests/resources-test.c index fa6ba2b2..92707297 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -206,3 +206,60 @@ TEST(free_without_remove) assert(a.link.next == a.link.prev && a.link.next == NULL); assert(b.link.next == b.link.prev && b.link.next == NULL); } + +static enum wl_iterator_result +client_resource_check(struct wl_resource* resource, void* data) +{ + /* Ensure there is no iteration over already freed resources. */ + assert(!wl_resource_get_user_data(resource)); + return WL_ITERATOR_CONTINUE; +} + +static void +resource_destroy_notify(struct wl_listener *l, void *data) +{ + struct wl_resource* resource = data; + struct wl_client* client = resource->client; + + wl_client_for_each_resource(client, client_resource_check, NULL); + + /* Set user data to flag the resource has been deleted. The resource should + * not be accessible from this point forward. */ + wl_resource_set_user_data(resource, client); +} + +TEST(resource_destroy_iteration) +{ + struct wl_display *display; + struct wl_client *client; + struct wl_resource *resource1; + struct wl_resource *resource2; + int s[2]; + + struct wl_listener destroy_listener1 = { + .notify = &resource_destroy_notify + }; + struct wl_listener destroy_listener2 = { + .notify = &resource_destroy_notify + }; + + assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + display = wl_display_create(); + assert(display); + client = wl_client_create(display, s[0]); + assert(client); + resource1 = wl_resource_create(client, &wl_callback_interface, 1, 0); + resource2 = wl_resource_create(client, &wl_callback_interface, 1, 0); + assert(resource1); + assert(resource2); + + wl_resource_add_destroy_listener(resource1, &destroy_listener1); + wl_resource_add_destroy_listener(resource2, &destroy_listener2); + + wl_client_destroy(client); + + close(s[0]); + close(s[1]); + + wl_display_destroy(display); +} From 6a7284c63234c465a194b23ad28d527fa997bbcc Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 25 Jan 2024 20:48:57 +0300 Subject: [PATCH 0968/1152] event-loop: use wl_priv_signal for the destroy signal Signed-off-by: Kirill Primak --- src/event-loop.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index c5cc34a6..45222f71 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -42,6 +42,7 @@ #include "wayland-util.h" #include "wayland-private.h" #include "wayland-server-core.h" +#include "wayland-server-private.h" #include "wayland-os.h" /** \cond INTERNAL */ @@ -73,7 +74,7 @@ struct wl_event_loop { struct wl_list idle_list; struct wl_list destroy_list; - struct wl_signal destroy_signal; + struct wl_priv_signal destroy_signal; struct wl_timer_heap timers; }; @@ -898,7 +899,7 @@ wl_event_loop_create(void) wl_list_init(&loop->idle_list); wl_list_init(&loop->destroy_list); - wl_signal_init(&loop->destroy_signal); + wl_priv_signal_init(&loop->destroy_signal); wl_timer_heap_init(&loop->timers, loop); @@ -921,7 +922,7 @@ wl_event_loop_create(void) WL_EXPORT void wl_event_loop_destroy(struct wl_event_loop *loop) { - wl_signal_emit(&loop->destroy_signal, loop); + wl_priv_signal_final_emit(&loop->destroy_signal, loop); wl_event_loop_process_destroy_list(loop); wl_timer_heap_release(&loop->timers); @@ -1147,7 +1148,7 @@ WL_EXPORT void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, struct wl_listener *listener) { - wl_signal_add(&loop->destroy_signal, listener); + wl_priv_signal_add(&loop->destroy_signal, listener); } /** Get the listener struct for the specified callback @@ -1163,5 +1164,5 @@ WL_EXPORT struct wl_listener * wl_event_loop_get_destroy_listener(struct wl_event_loop *loop, wl_notify_func_t notify) { - return wl_signal_get(&loop->destroy_signal, notify); + return wl_priv_signal_get(&loop->destroy_signal, notify); } From 9c4213ed3eb3942766712df936775d827b846d0b Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Mon, 25 Oct 2021 04:34:49 +0200 Subject: [PATCH 0969/1152] server: add wl_client_get_user_data/wl_client_set_user_data The only way to attach some data to a wl_client seems to be setting up a destroy listener and use wl_container_of. Let's make it straight forward to attach some data. Having an explicit destroy callback for the user data makes managing the user data lifetime much more convenient. All other callbacks, be they wl_resource request listeners, destroy listeners or destructors, or wl_client destroy listeners, can assume that the wl_client user data still exists if it was set. Otherwise making that guarantee would be complicated. Co-authored-by: Pekka Paalanen Signed-off-by: Sebastian Wick --- src/wayland-server-core.h | 10 +++++++++ src/wayland-server.c | 46 +++++++++++++++++++++++++++++++++++++++ tests/client-test.c | 15 +++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index df958211..00a54433 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -365,6 +365,16 @@ wl_client_for_each_resource(struct wl_client *client, wl_client_for_each_resource_iterator_func_t iterator, void *user_data); +typedef void (*wl_user_data_destroy_func_t)(void *data); + +void +wl_client_set_user_data(struct wl_client *client, + void *data, + wl_user_data_destroy_func_t dtor); + +void * +wl_client_get_user_data(struct wl_client *client); + /** \class wl_listener * * \brief A single listener for Wayland signals diff --git a/src/wayland-server.c b/src/wayland-server.c index 9fd12273..1e079a3b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -85,6 +85,8 @@ struct wl_client { gid_t gid; bool error; struct wl_priv_signal resource_created_signal; + void *data; + wl_user_data_destroy_func_t data_dtor; }; struct wl_display { @@ -943,6 +945,10 @@ wl_client_destroy(struct wl_client *client) wl_list_remove(&client->link); wl_list_remove(&client->resource_created_signal.listener_list); + + if (client->data_dtor) + client->data_dtor(client->data); + free(client); } @@ -2469,6 +2475,46 @@ wl_client_new_object(struct wl_client *client, return resource; } +/** Set the client's user data + * + * User data is whatever the caller wants to store. Use dtor if + * the user data needs freeing as the very last step of destroying + * the client. + * + * \param client The client object + * \param data The user data pointer + * \param dtor Destroy function to be called after all resources have been + * destroyed and all destroy listeners have been called. Can be NULL. + * + * The argument to the destroy function is the user data pointer. If the + * destroy function is not NULL, it will be called even if user data is NULL. + * + * \since 1.22.90 + * \sa wl_client_get_user_data + */ +WL_EXPORT void +wl_client_set_user_data(struct wl_client *client, + void *data, + wl_user_data_destroy_func_t dtor) +{ + client->data = data; + client->data_dtor = dtor; +} + +/** Get the client's user data + * + * \param client The client object + * \return The user data pointer + * + * \since 1.22.90 + * \sa wl_client_set_user_data + */ +WL_EXPORT void * +wl_client_get_user_data(struct wl_client *client) +{ + return client->data; +} + struct wl_global * wl_display_add_global(struct wl_display *display, const struct wl_interface *interface, diff --git a/tests/client-test.c b/tests/client-test.c index 47be83fc..659bac10 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -80,12 +80,21 @@ client_late_destroy_notify(struct wl_listener *l, void *data) listener->late_done = true; } +static void +client_user_data_destroy(void *data) +{ + bool *user_data_destroyed = data; + + *user_data_destroyed = true; +} + TEST(client_destroy_listener) { struct wl_display *display; struct wl_client *client; struct wl_resource *resource; struct client_destroy_listener a, b; + bool user_data_destroyed = false; int s[2]; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); @@ -94,6 +103,9 @@ TEST(client_destroy_listener) client = wl_client_create(display, s[0]); assert(client); + wl_client_set_user_data(client, &user_data_destroyed, client_user_data_destroy); + assert(wl_client_get_user_data(client) == &user_data_destroyed); + resource = wl_resource_create(client, &wl_callback_interface, 1, 0); assert(resource); @@ -128,6 +140,8 @@ TEST(client_destroy_listener) wl_list_remove(&a.resource_listener.link); wl_list_remove(&a.late_listener.link); + assert(!user_data_destroyed); + wl_client_destroy(client); assert(!a.done); @@ -136,6 +150,7 @@ TEST(client_destroy_listener) assert(b.done); assert(b.resource_done); assert(b.late_done); + assert(user_data_destroyed); close(s[0]); close(s[1]); From a74aa93394a6d572eb48b1898658dad3e0c5f720 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Oct 2023 13:25:44 +0200 Subject: [PATCH 0970/1152] protocol: mention wl_surface events from wl_output.{scale,transform} The wl_output events should not be used anymore for guessing the preferred scale and transform of a surface. We have explicit events for that now. Signed-off-by: Simon Ser --- protocol/wayland.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 93f9d553..31daa748 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2757,6 +2757,10 @@ The geometry event will be followed by a done event (starting from version 2). + Clients should use wl_surface.preferred_buffer_transform instead of the + transform advertised by this event to find the preferred buffer + transform to use for a surface. + Note: wl_output only advertises partial information about the output position and identification. Some compositors, for instance those not implementing a desktop-style output layout or those exposing virtual @@ -2862,12 +2866,9 @@ displays where applications rendering at the native resolution would be too small to be legible. - It is intended that scaling aware clients track the - current output of a surface, and if it is on a scaled - output it should use wl_surface.set_buffer_scale with - the scale of the output. That way the compositor can - avoid scaling the surface, and the client can supply - a higher detail image. + Clients should use wl_surface.preferred_buffer_scale + instead of this event to find the preferred buffer + scale to use for a surface. The scale event will be followed by a done event. From 791912c67867b84e15f7a70d5f716c9dd8c2c01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 19 Jan 2024 16:08:21 +0000 Subject: [PATCH 0971/1152] compat: prefer waitpid() over waitid() while both are defined by POSIX, waitpid() is more common than waitid(). Signed-off-by: Sebastien Marie --- tests/test-compositor.c | 25 +++++++++++-------------- tests/test-runner.c | 21 ++++++++------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 49d76d6d..8648fb69 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -103,26 +103,23 @@ handle_client_destroy(void *data) { struct client_info *ci = data; struct display *d; - siginfo_t status; + int status; d = ci->display; - assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1); + assert(waitpid(ci->pid, &status, 0) != -1); - switch (status.si_code) { - case CLD_KILLED: - case CLD_DUMPED: + if (WIFSIGNALED(status)) { fprintf(stderr, "Client '%s' was killed by signal %d\n", - ci->name, status.si_status); - ci->kill_code = status.si_status; - break; - case CLD_EXITED: - if (status.si_status != EXIT_SUCCESS) - fprintf(stderr, "Client '%s' exited with code %d\n", - ci->name, status.si_status); + ci->name, WTERMSIG(status)); + ci->kill_code = WTERMSIG(status); - ci->exit_code = status.si_status; - break; + } else if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != EXIT_SUCCESS) + fprintf(stderr, "Client '%s' exited with code %d\n", + ci->name, WEXITSTATUS(status)); + + ci->exit_code = WEXITSTATUS(status); } ++d->clients_terminated_no; diff --git a/tests/test-runner.c b/tests/test-runner.c index d07dab15..ea2715e6 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -315,7 +315,7 @@ int main(int argc, char *argv[]) const struct test *t; pid_t pid; int total, pass; - siginfo_t info; + int info; if (isatty(fileno(stderr))) is_atty = 1; @@ -358,37 +358,32 @@ int main(int argc, char *argv[]) if (pid == 0) run_test(t); /* never returns */ - if (waitid(P_PID, pid, &info, WEXITED)) { + if (waitpid(pid, &info, 0) == -1) { stderr_set_color(RED); - fprintf(stderr, "waitid failed: %s\n", + fprintf(stderr, "waitpid failed: %s\n", strerror(errno)); stderr_reset_color(); abort(); } - switch (info.si_code) { - case CLD_EXITED: - if (info.si_status == EXIT_SUCCESS) + if (WIFEXITED(info)) { + if (WEXITSTATUS(info) == EXIT_SUCCESS) success = !t->must_fail; else success = t->must_fail; stderr_set_color(success ? GREEN : RED); fprintf(stderr, "test \"%s\":\texit status %d", - t->name, info.si_status); + t->name, WEXITSTATUS(info)); - break; - case CLD_KILLED: - case CLD_DUMPED: + } else if (WIFSIGNALED(info)) { if (t->must_fail) success = 1; stderr_set_color(success ? GREEN : RED); fprintf(stderr, "test \"%s\":\tsignal %d", - t->name, info.si_status); - - break; + t->name, WTERMSIG(info)); } if (success) { From d80bce5f1a0917c013aac54e3f951ffe740d0cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Fri, 19 Jan 2024 16:09:27 +0000 Subject: [PATCH 0972/1152] build: fix build and provide compat for OpenBSD - wayland-egl-abi-check: try to use llvm-nm first instead of BSD nm (incompatible options) - avoid forcing _POSIX_C_SOURCE=200809L (SOCK_CLOEXEC become available) - epoll(7) is provided by a userspace wrapper around kqueue(2) as FreeBSD - when using SO_PEERCRED, the struct to use is `struct sockpeercred` instead of `struct ucred` on OpenBSD - provide a compatibility layer for count_open_fds() using sysctl(2) as FreeBSD Signed-off-by: Sebastien Marie --- egl/meson.build | 2 +- meson.build | 4 ++-- src/wayland-os.c | 4 ++++ tests/test-helpers.c | 27 +++++++++++++++++++++++++++ tests/test-runner.c | 7 +++++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/egl/meson.build b/egl/meson.build index 76c6ee21..5c62ac1e 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -13,7 +13,7 @@ if get_option('tests') wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') test('wayland-egl abi check', wayland_egl_abi_check) - nm_path = find_program('nm').full_path() + nm_path = find_program(['llvm-nm', 'nm']).full_path() test( 'wayland-egl symbols check', diff --git a/meson.build b/meson.build index b879df7b..431ebb7e 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,7 @@ config_h.set_quoted('PACKAGE', meson.project_name()) config_h.set_quoted('PACKAGE_VERSION', meson.project_version()) cc_args = [] -if host_machine.system() != 'freebsd' +if host_machine.system() not in ['freebsd', 'openbsd'] cc_args += ['-D_POSIX_C_SOURCE=200809L'] endif add_project_arguments(cc_args, language: 'c') @@ -69,7 +69,7 @@ endif config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec) if get_option('libraries') - if host_machine.system() == 'freebsd' + if host_machine.system() in ['freebsd', 'openbsd'] # When building for FreeBSD, epoll(7) is provided by a userspace # wrapper around kqueue(2). epoll_dep = dependency('epoll-shim') diff --git a/src/wayland-os.c b/src/wayland-os.c index a0db2e84..f00ead4b 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -111,7 +111,11 @@ int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) { socklen_t len; +#if defined(__OpenBSD__) + struct sockpeercred ucred; +#else struct ucred ucred; +#endif len = sizeof(ucred); if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) diff --git a/tests/test-helpers.c b/tests/test-helpers.c index 35357445..1af813bb 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -61,6 +61,33 @@ count_open_fds(void) assert(error == 0 && "sysctl KERN_PROC_NFDS failed."); return nfds; } +#elif defined(__OpenBSD__) +#include + +/* + * On OpenBSD, get file descriptor information using sysctl() + */ +int +count_open_fds(void) +{ + int error; + int mib[6]; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_FILE; + mib[2] = KERN_FILE_BYPID; + mib[3] = getpid(); + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + /* find the size required to store all the entries */ + error = sysctl(mib, 6, NULL, &size, NULL, 0); + assert(error != -1 && "sysctl KERN_FILE_BYPID failed."); + + /* return the current number of entries */ + return size / sizeof(struct kinfo_file); +} #else int count_open_fds(void) diff --git a/tests/test-runner.c b/tests/test-runner.c index ea2715e6..9a50d1dd 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -308,6 +308,13 @@ is_debugger_attached(void) return rc; } +#else +static int +is_debugger_attached(void) +{ + /* 0=debugger can't be determined */ + return 0; +} #endif int main(int argc, char *argv[]) From 47de87263c88d3e23c7d7eb6d56ff75ddc8a02ef Mon Sep 17 00:00:00 2001 From: Thomas Lukaszewicz Date: Fri, 5 Jan 2024 00:50:49 +0000 Subject: [PATCH 0973/1152] Mitigate UAF crashes due to wl_client_destroy reentrancy There are situations in which a call into wl_client_destroy() can result in a reentrant call into wl_client_destroy() - which results in UAF / double free crashes. For example, this can occur in the following scenario. 1. Server receives a message notifying it that a client has disconnected (WL_EVENT_HANGUP [1]) 2. This beings client destruction with a call to wl_client_destroy() 3. wl_client_destroy() kicks off callbacks as client-associated resources are cleaned up and their destructors and destruction signals are invoked. 4. These callbacks eventually lead to an explicit call to wl_display_flush_clients() as the server attempts to flush events to other connected clients. 5. Since the client has already begun destruction, when it is reached in the iteration the flush fails wl_client_destroy() is called again [2]. This patch guards against this reentrant condition by removing the client from the display's client list when wl_client_destroy() is first called. This prevents access / iteration over the client after wl_client_destroy() is called. In the example above, wl_display_flush_clients() will pass over the client currently undergoing destruction and the reentrant call is avoided. [1] https://gitlab.freedesktop.org/wayland/wayland/-/blob/8f499bf4045f88f3a4b4b0a445befca467bebe20/src/wayland-server.c#L342 [2] https://gitlab.freedesktop.org/wayland/wayland/-/blob/8f499bf4045f88f3a4b4b0a445befca467bebe20/src/wayland-server.c#L1512 Signed-off-by: Thomas Lukaszewicz [thomaslukaszewicz@gmail.com](mailto:thomaslukaszewicz@gmail.com) --- src/wayland-server.c | 13 +++++++++++- tests/client-test.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 1e079a3b..78ff4055 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -933,6 +933,18 @@ wl_client_get_destroy_late_listener(struct wl_client *client, WL_EXPORT void wl_client_destroy(struct wl_client *client) { + + /* wl_client_destroy() should not be called twice for the same client. */ + if (wl_list_empty(&client->link)) { + client->error = 1; + wl_log("wl_client_destroy: encountered re-entrant client destruction.\n"); + return; + } + + wl_list_remove(&client->link); + /* Keep the client link safe to inspect. */ + wl_list_init(&client->link); + wl_priv_signal_final_emit(&client->destroy_signal, client); wl_client_flush(client); @@ -943,7 +955,6 @@ wl_client_destroy(struct wl_client *client) wl_priv_signal_final_emit(&client->destroy_late_signal, client); - wl_list_remove(&client->link); wl_list_remove(&client->resource_created_signal.listener_list); if (client->data_dtor) diff --git a/tests/client-test.c b/tests/client-test.c index 659bac10..5585c0cd 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -158,3 +158,50 @@ TEST(client_destroy_listener) wl_display_destroy(display); } +static void +client_destroy_remove_link_notify(struct wl_listener *l, void *data) +{ + struct wl_client *client = data; + struct client_destroy_listener *listener = + wl_container_of(l, listener, listener); + + /* The client destruction signal should not be emitted more than once. */ + assert(!listener->done); + listener->done = true; + + /* The client should have been removed from the display's list. */ + assert(wl_list_empty(wl_client_get_link(client))); +} + +/* + * Tests that wl_client_destroy() will remove the client from the display's + * client list to prevent client access during destruction. + */ +TEST(client_destroy_removes_link) +{ + struct wl_display *display; + struct wl_client *client; + struct client_destroy_listener destroy_listener; + int s[2]; + + assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + display = wl_display_create(); + assert(display); + client = wl_client_create(display, s[0]); + assert(client); + + destroy_listener.listener.notify = client_destroy_remove_link_notify; + destroy_listener.done = false; + wl_client_add_destroy_listener(client, &destroy_listener.listener); + + assert(wl_client_get_destroy_listener(client, + client_destroy_remove_link_notify) == &destroy_listener.listener); + + wl_client_destroy(client); + assert(destroy_listener.done); + + close(s[0]); + close(s[1]); + + wl_display_destroy(display); +} From 155dd63b58b8fc10d58fa03d6398d1673cea6062 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 15 Feb 2024 10:37:34 +0100 Subject: [PATCH 0974/1152] Introduce enum wl_arg_type This is less cryptic to read than letters, and allows the compiler to check switch statements exhaustiveness. Signed-off-by: Simon Ser --- src/connection.c | 161 +++++++++++++++++++++--------------------- src/wayland-client.c | 20 +++--- src/wayland-private.h | 16 ++++- src/wayland-server.c | 6 +- 4 files changed, 111 insertions(+), 92 deletions(-) diff --git a/src/connection.c b/src/connection.c index b89166fb..3eb66222 100644 --- a/src/connection.c +++ b/src/connection.c @@ -441,14 +441,14 @@ get_next_argument(const char *signature, struct argument_details *details) details->nullable = 0; for(; *signature; ++signature) { switch(*signature) { - case 'i': - case 'u': - case 'f': - case 's': - case 'o': - case 'n': - case 'a': - case 'h': + case WL_ARG_INT: + case WL_ARG_UINT: + case WL_ARG_FIXED: + case WL_ARG_STRING: + case WL_ARG_OBJECT: + case WL_ARG_NEW_ID: + case WL_ARG_ARRAY: + case WL_ARG_FD: details->type = *signature; return signature + 1; case '?': @@ -465,14 +465,14 @@ arg_count_for_signature(const char *signature) int count = 0; for(; *signature; ++signature) { switch(*signature) { - case 'i': - case 'u': - case 'f': - case 's': - case 'o': - case 'n': - case 'a': - case 'h': + case WL_ARG_INT: + case WL_ARG_UINT: + case WL_ARG_FIXED: + case WL_ARG_STRING: + case WL_ARG_OBJECT: + case WL_ARG_NEW_ID: + case WL_ARG_ARRAY: + case WL_ARG_FD: ++count; } } @@ -505,32 +505,30 @@ wl_argument_from_va_list(const char *signature, union wl_argument *args, sig_iter = get_next_argument(sig_iter, &arg); switch(arg.type) { - case 'i': + case WL_ARG_INT: args[i].i = va_arg(ap, int32_t); break; - case 'u': + case WL_ARG_UINT: args[i].u = va_arg(ap, uint32_t); break; - case 'f': + case WL_ARG_FIXED: args[i].f = va_arg(ap, wl_fixed_t); break; - case 's': + case WL_ARG_STRING: args[i].s = va_arg(ap, const char *); break; - case 'o': + case WL_ARG_OBJECT: args[i].o = va_arg(ap, struct wl_object *); break; - case 'n': + case WL_ARG_NEW_ID: args[i].o = va_arg(ap, struct wl_object *); break; - case 'a': + case WL_ARG_ARRAY: args[i].a = va_arg(ap, struct wl_array *); break; - case 'h': + case WL_ARG_FD: args[i].h = va_arg(ap, int32_t); break; - case '\0': - return; } } } @@ -544,7 +542,7 @@ wl_closure_clear_fds(struct wl_closure *closure) for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type == 'h') + if (arg.type == WL_ARG_FD) closure->args[i].h = -1; } } @@ -622,30 +620,30 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode, signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'f': - case 'u': - case 'i': + case WL_ARG_FIXED: + case WL_ARG_UINT: + case WL_ARG_INT: break; - case 's': + case WL_ARG_STRING: if (!arg.nullable && args[i].s == NULL) goto err_null; break; - case 'o': + case WL_ARG_OBJECT: if (!arg.nullable && args[i].o == NULL) goto err_null; break; - case 'n': + case WL_ARG_NEW_ID: object = args[i].o; if (object == NULL) goto err_null; closure->args[i].n = object ? object->id : 0; break; - case 'a': + case WL_ARG_ARRAY: if (args[i].a == NULL) goto err_null; break; - case 'h': + case WL_ARG_FD: fd = args[i].h; dup_fd = wl_os_dupfd_cloexec(fd, 0); if (dup_fd < 0) { @@ -731,7 +729,7 @@ wl_connection_demarshal(struct wl_connection *connection, for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type != 'h' && p + 1 > end) { + if (arg.type != WL_ARG_FD && p + 1 > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, @@ -741,16 +739,16 @@ wl_connection_demarshal(struct wl_connection *connection, } switch (arg.type) { - case 'u': + case WL_ARG_UINT: closure->args[i].u = *p++; break; - case 'i': + case WL_ARG_INT: closure->args[i].i = *p++; break; - case 'f': + case WL_ARG_FIXED: closure->args[i].f = *p++; break; - case 's': + case WL_ARG_STRING: length = *p++; if (length == 0 && !arg.nullable) { @@ -789,7 +787,7 @@ wl_connection_demarshal(struct wl_connection *connection, closure->args[i].s = s; p = next; break; - case 'o': + case WL_ARG_OBJECT: id = *p++; closure->args[i].n = id; @@ -801,7 +799,7 @@ wl_connection_demarshal(struct wl_connection *connection, goto err; } break; - case 'n': + case WL_ARG_NEW_ID: id = *p++; closure->args[i].n = id; @@ -824,7 +822,7 @@ wl_connection_demarshal(struct wl_connection *connection, } break; - case 'a': + case WL_ARG_ARRAY: length = *p++; length_in_u32 = div_roundup(length, sizeof *p); @@ -845,7 +843,7 @@ wl_connection_demarshal(struct wl_connection *connection, closure->args[i].a = array_extra++; p = next; break; - case 'h': + case WL_ARG_FD: if (connection->fds_in.tail == connection->fds_in.head) { wl_log("file descriptor expected, " "object (%d), message %s(%s)\n", @@ -909,7 +907,7 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'o': + case WL_ARG_OBJECT: id = closure->args[i].n; closure->args[i].o = NULL; @@ -936,6 +934,9 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) return -1; } closure->args[i].o = object; + break; + default: + break; } } @@ -956,27 +957,27 @@ convert_arguments_to_ffi(const char *signature, uint32_t flags, sig_iter = get_next_argument(sig_iter, &arg); switch(arg.type) { - case 'i': + case WL_ARG_INT: ffi_types[i] = &ffi_type_sint32; ffi_args[i] = &args[i].i; break; - case 'u': + case WL_ARG_UINT: ffi_types[i] = &ffi_type_uint32; ffi_args[i] = &args[i].u; break; - case 'f': + case WL_ARG_FIXED: ffi_types[i] = &ffi_type_sint32; ffi_args[i] = &args[i].f; break; - case 's': + case WL_ARG_STRING: ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].s; break; - case 'o': + case WL_ARG_OBJECT: ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].o; break; - case 'n': + case WL_ARG_NEW_ID: if (flags & WL_CLOSURE_INVOKE_CLIENT) { ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].o; @@ -985,11 +986,11 @@ convert_arguments_to_ffi(const char *signature, uint32_t flags, ffi_args[i] = &args[i].n; } break; - case 'a': + case WL_ARG_ARRAY: ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].a; break; - case 'h': + case WL_ARG_FD: ffi_types[i] = &ffi_type_sint32; ffi_args[i] = &args[i].h; break; @@ -1056,7 +1057,7 @@ copy_fds_to_connection(struct wl_closure *closure, count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type != 'h') + if (arg.type != WL_ARG_FD) continue; fd = closure->args[i].h; @@ -1087,16 +1088,16 @@ buffer_size_for_closure(struct wl_closure *closure) signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'h': + case WL_ARG_FD: break; - case 'u': - case 'i': - case 'f': - case 'o': - case 'n': + case WL_ARG_UINT: + case WL_ARG_INT: + case WL_ARG_FIXED: + case WL_ARG_OBJECT: + case WL_ARG_NEW_ID: buffer_size++; break; - case 's': + case WL_ARG_STRING: if (closure->args[i].s == NULL) { buffer_size++; break; @@ -1105,7 +1106,7 @@ buffer_size_for_closure(struct wl_closure *closure) size = strlen(closure->args[i].s) + 1; buffer_size += 1 + div_roundup(size, sizeof(uint32_t)); break; - case 'a': + case WL_ARG_ARRAY: if (closure->args[i].a == NULL) { buffer_size++; break; @@ -1143,29 +1144,29 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type == 'h') + if (arg.type == WL_ARG_FD) continue; if (p + 1 > end) goto overflow; switch (arg.type) { - case 'u': + case WL_ARG_UINT: *p++ = closure->args[i].u; break; - case 'i': + case WL_ARG_INT: *p++ = closure->args[i].i; break; - case 'f': + case WL_ARG_FIXED: *p++ = closure->args[i].f; break; - case 'o': + case WL_ARG_OBJECT: *p++ = closure->args[i].o ? closure->args[i].o->id : 0; break; - case 'n': + case WL_ARG_NEW_ID: *p++ = closure->args[i].n; break; - case 's': + case WL_ARG_STRING: if (closure->args[i].s == NULL) { *p++ = 0; break; @@ -1180,7 +1181,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, memcpy(p, closure->args[i].s, size); p += div_roundup(size, sizeof *p); break; - case 'a': + case WL_ARG_ARRAY: if (closure->args[i].a == NULL) { *p++ = 0; break; @@ -1196,7 +1197,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, memcpy(p, closure->args[i].a->data, size); p += div_roundup(size, sizeof *p); break; - default: + case WL_ARG_FD: break; } } @@ -1320,13 +1321,13 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, fprintf(f, ", "); switch (arg.type) { - case 'u': + case WL_ARG_UINT: fprintf(f, "%u", closure->args[i].u); break; - case 'i': + case WL_ARG_INT: fprintf(f, "%d", closure->args[i].i); break; - case 'f': + case WL_ARG_FIXED: /* The magic number 390625 is 1e8 / 256 */ if (closure->args[i].f >= 0) { fprintf(f, "%d.%08d", @@ -1339,13 +1340,13 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, -390625 * (closure->args[i].f % 256)); } break; - case 's': + case WL_ARG_STRING: if (closure->args[i].s) fprintf(f, "\"%s\"", closure->args[i].s); else fprintf(f, "nil"); break; - case 'o': + case WL_ARG_OBJECT: if (closure->args[i].o) fprintf(f, "%s#%u", closure->args[i].o->interface->name, @@ -1353,7 +1354,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, else fprintf(f, "nil"); break; - case 'n': + case WL_ARG_NEW_ID: if (n_parse) nval = n_parse(&closure->args[i]); else @@ -1368,10 +1369,10 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, else fprintf(f, "nil"); break; - case 'a': + case WL_ARG_ARRAY: fprintf(f, "array[%zu]", closure->args[i].a->size); break; - case 'h': + case WL_ARG_FD: fprintf(f, "fd %d", closure->args[i].h); break; } @@ -1394,7 +1395,7 @@ wl_closure_close_fds(struct wl_closure *closure) for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type == 'h' && closure->args[i].h != -1) + if (arg.type == WL_ARG_FD && closure->args[i].h != -1) close(closure->args[i].h); } diff --git a/src/wayland-client.c b/src/wayland-client.c index 94438e30..2954652d 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -258,8 +258,8 @@ validate_closure_objects(struct wl_closure *closure) for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'n': - case 'o': + case WL_ARG_NEW_ID: + case WL_ARG_OBJECT: proxy = (struct wl_proxy *) closure->args[i].o; if (proxy && proxy->flags & WL_PROXY_FLAG_DESTROYED) closure->args[i].o = NULL; @@ -286,8 +286,8 @@ destroy_queued_closure(struct wl_closure *closure) for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'n': - case 'o': + case WL_ARG_NEW_ID: + case WL_ARG_OBJECT: proxy = (struct wl_proxy *) closure->args[i].o; if (proxy) wl_proxy_unref(proxy); @@ -421,7 +421,7 @@ message_count_fds(const char *signature) count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type == 'h') + if (arg.type == WL_ARG_FD) fds++; } @@ -735,13 +735,15 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'n': + case WL_ARG_NEW_ID: new_proxy = proxy_create(proxy, interface, version); if (new_proxy == NULL) return NULL; args[i].o = &new_proxy->object; break; + default: + break; } } @@ -1490,7 +1492,7 @@ create_proxies(struct wl_proxy *sender, struct wl_closure *closure) for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'n': + case WL_ARG_NEW_ID: id = closure->args[i].n; if (id == 0) { closure->args[i].o = NULL; @@ -1523,8 +1525,8 @@ increase_closure_args_refcount(struct wl_closure *closure) for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'n': - case 'o': + case WL_ARG_NEW_ID: + case WL_ARG_OBJECT: proxy = (struct wl_proxy *) closure->args[i].o; if (proxy) proxy->refcount++; diff --git a/src/wayland-private.h b/src/wayland-private.h index 6b506584..a370763d 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -48,6 +48,20 @@ #define WL_MAP_MAX_OBJECTS 0x00f00000 #define WL_CLOSURE_MAX_ARGS 20 +/** + * Argument types used in signatures. + */ +enum wl_arg_type { + WL_ARG_INT = 'i', + WL_ARG_UINT = 'u', + WL_ARG_FIXED = 'f', + WL_ARG_STRING = 's', + WL_ARG_OBJECT = 'o', + WL_ARG_NEW_ID = 'n', + WL_ARG_ARRAY = 'a', + WL_ARG_FD = 'h', +}; + struct wl_object { const struct wl_interface *interface; const void *implementation; @@ -149,7 +163,7 @@ struct wl_closure { }; struct argument_details { - char type; + enum wl_arg_type type; int nullable; }; diff --git a/src/wayland-server.c b/src/wayland-server.c index 78ff4055..9726807e 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -191,8 +191,8 @@ verify_objects(struct wl_resource *resource, uint32_t opcode, for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { - case 'n': - case 'o': + case WL_ARG_NEW_ID: + case WL_ARG_OBJECT: res = (struct wl_resource *) (args[i].o); if (res && res->client != resource->client) { wl_log("compositor bug: The compositor " @@ -202,6 +202,8 @@ verify_objects(struct wl_resource *resource, uint32_t opcode, object->interface->events[opcode].name); return false; } + default: + break; } } return true; From 830883e5b2d3ec20a4f73258bdd97d12e5e9c9bc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Feb 2024 12:23:34 +0100 Subject: [PATCH 0975/1152] connection: simplify wl_closure_lookup_objects() loop Decrease the indentation a bit. No functional change. Signed-off-by: Simon Ser --- src/connection.c | 55 +++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/connection.c b/src/connection.c index 3eb66222..0cfb611d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -906,38 +906,35 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - switch (arg.type) { - case WL_ARG_OBJECT: - id = closure->args[i].n; - closure->args[i].o = NULL; + if (arg.type != WL_ARG_OBJECT) + continue; - object = wl_map_lookup(objects, id); - if (wl_object_is_zombie(objects, id)) { - /* references object we've already - * destroyed client side */ - object = NULL; - } else if (object == NULL && id != 0) { - wl_log("unknown object (%u), message %s(%s)\n", - id, message->name, message->signature); - errno = EINVAL; - return -1; - } + id = closure->args[i].n; + closure->args[i].o = NULL; - if (object != NULL && message->types[i] != NULL && - !wl_interface_equal((object)->interface, - message->types[i])) { - wl_log("invalid object (%u), type (%s), " - "message %s(%s)\n", - id, (object)->interface->name, - message->name, message->signature); - errno = EINVAL; - return -1; - } - closure->args[i].o = object; - break; - default: - break; + object = wl_map_lookup(objects, id); + if (wl_object_is_zombie(objects, id)) { + /* references object we've already + * destroyed client side */ + object = NULL; + } else if (object == NULL && id != 0) { + wl_log("unknown object (%u), message %s(%s)\n", + id, message->name, message->signature); + errno = EINVAL; + return -1; } + + if (object != NULL && message->types[i] != NULL && + !wl_interface_equal((object)->interface, + message->types[i])) { + wl_log("invalid object (%u), type (%s), " + "message %s(%s)\n", + id, (object)->interface->name, + message->name, message->signature); + errno = EINVAL; + return -1; + } + closure->args[i].o = object; } return 0; From 7a1e7dd54963fad696aa7a1305440945ba3761d1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Feb 2024 12:28:39 +0100 Subject: [PATCH 0976/1152] client: simplify create_outgoing_proxy() loop Decrease the indentation a bit. No functional change. Signed-off-by: Simon Ser --- src/wayland-client.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 2954652d..3e61dad3 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -733,18 +733,14 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); + if (arg.type != WL_ARG_NEW_ID) + continue; - switch (arg.type) { - case WL_ARG_NEW_ID: - new_proxy = proxy_create(proxy, interface, version); - if (new_proxy == NULL) - return NULL; + new_proxy = proxy_create(proxy, interface, version); + if (new_proxy == NULL) + return NULL; - args[i].o = &new_proxy->object; - break; - default: - break; - } + args[i].o = &new_proxy->object; } return new_proxy; From 440defbd2ba3379b0519ce4f0381bdbe181ce58d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Feb 2024 12:30:03 +0100 Subject: [PATCH 0977/1152] client: simplify create_proxies() loop Decrease the indentation a bit. No functional change. Signed-off-by: Simon Ser --- src/wayland-client.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 3e61dad3..665fe552 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1487,22 +1487,19 @@ create_proxies(struct wl_proxy *sender, struct wl_closure *closure) count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - switch (arg.type) { - case WL_ARG_NEW_ID: - id = closure->args[i].n; - if (id == 0) { - closure->args[i].o = NULL; - break; - } - proxy = wl_proxy_create_for_id(sender, id, - closure->message->types[i]); - if (proxy == NULL) - return -1; - closure->args[i].o = (struct wl_object *)proxy; - break; - default: - break; + if (arg.type != WL_ARG_NEW_ID) + continue; + + id = closure->args[i].n; + if (id == 0) { + closure->args[i].o = NULL; + continue; } + proxy = wl_proxy_create_for_id(sender, id, + closure->message->types[i]); + if (proxy == NULL) + return -1; + closure->args[i].o = (struct wl_object *)proxy; } return 0; From 44b1c0c737f3e877d98ea99459cda828bc1ff0a5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 6 Mar 2024 19:08:53 +0100 Subject: [PATCH 0978/1152] connection: use enum wl_arg_type in wl_message_count_arrays() Missed it in 155dd63b58b8 ("Introduce enum wl_arg_type"). Signed-off-by: Simon Ser --- src/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index 0cfb611d..a58b7a7c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -410,7 +410,7 @@ wl_message_count_arrays(const struct wl_message *message) int i, arrays; for (i = 0, arrays = 0; message->signature[i]; i++) { - if (message->signature[i] == 'a') + if (message->signature[i] == WL_ARG_ARRAY) arrays++; } From aa2a6d560bb2ec39b0643103942dc7b3dfa5976c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 6 Mar 2024 11:19:09 +0100 Subject: [PATCH 0979/1152] protocol: document that color channels provide electrical values Expand the work done in [1] to document that all channels store electrical values. See the discussion in [2]. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/316 [2]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/250#note_2311377 Signed-off-by: Simon Ser --- protocol/wayland.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 31daa748..d817a6e2 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -479,8 +479,10 @@ client provides and updates the contents is defined by the buffer factory interface. - If the buffer uses a format that has an alpha channel, the alpha channel - is assumed to be premultiplied in the electrical color channel values + Color channels are assumed to be electrical rather than optical (in other + words, encoded with a transfer function) unless otherwise specified. If + the buffer uses a format that has an alpha channel, the alpha channel is + assumed to be premultiplied into the electrical color channel values (after transfer function encoding) unless otherwise specified. Note, because wl_buffer objects are created from multiple independent From 8a7ecd774c4032f30949665b42910c2d2cae53f2 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 24 Mar 2024 19:43:58 -0400 Subject: [PATCH 0980/1152] util: fix undefined behavior in wl_array_for_each If a wl_array has size zero, wl_array_for_each computes NULL + 0 to get to the end pointer. This should be fine, and indeed it would be fine in C++. But the C specification has a mistake here and it is actually undefined behavior. See https://davidben.net/2024/01/15/empty-slices.html Clang's -fsanitize=undefined flags this. I ran into this in Chromium's build with wayland-scanner on one of our XML files. ../../third_party/wayland/src/src/scanner.c:1853:2: runtime error: applying zero offset to null pointer #0 0x55c979b8e02c in emit_code third_party/wayland/src/src/scanner.c:1853:2 #1 0x55c979b89323 in main third_party/wayland/src/src/scanner.c #2 0x7f8dfdb8c6c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #3 0x7f8dfdb8c784 in __libc_start_main csu/../csu/libc-start.c:360:3 #4 0x55c979b70f39 in _start (...) An empty XML file is sufficient to hit this case, so I've added it as a test. To reproduce, undo the fix and include only the test, then build with: CC=clang CFLAGS="-fno-sanitize-recover=undefined" meson build/ -Db_sanitize=undefined -Db_lundef=false ninja -C build test Signed-off-by: David Benjamin --- src/wayland-util.h | 1 + tests/data/empty-client.h | 83 +++++++++++++++++++++++++++++++++++++++ tests/data/empty-code.c | 20 ++++++++++ tests/data/empty-server.h | 58 +++++++++++++++++++++++++++ tests/data/empty.xml | 7 ++++ tests/scanner-test-gen.sh | 4 ++ tests/scanner-test.sh | 4 ++ 7 files changed, 177 insertions(+) create mode 100644 tests/data/empty-client.h create mode 100644 tests/data/empty-code.c create mode 100644 tests/data/empty-server.h create mode 100644 tests/data/empty.xml diff --git a/src/wayland-util.h b/src/wayland-util.h index c99069cc..929a34f3 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -598,6 +598,7 @@ wl_array_copy(struct wl_array *array, struct wl_array *source); */ #define wl_array_for_each(pos, array) \ for (pos = (array)->data; \ + (array)->size != 0 && \ (const char *) pos < ((const char *) (array)->data + (array)->size); \ (pos)++) diff --git a/tests/data/empty-client.h b/tests/data/empty-client.h new file mode 100644 index 00000000..bf1264a4 --- /dev/null +++ b/tests/data/empty-client.h @@ -0,0 +1,83 @@ +/* SCANNER TEST */ + +#ifndef EMPTY_CLIENT_PROTOCOL_H +#define EMPTY_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_empty The empty protocol + * @section page_ifaces_empty Interfaces + * - @subpage page_iface_empty - + */ +struct empty; + +#ifndef EMPTY_INTERFACE +#define EMPTY_INTERFACE +/** + * @page page_iface_empty empty + * @section page_iface_empty_api API + * See @ref iface_empty. + */ +/** + * @defgroup iface_empty The empty interface + */ +extern const struct wl_interface empty_interface; +#endif + +#define EMPTY_EMPTY 0 + + +/** + * @ingroup iface_empty + */ +#define EMPTY_EMPTY_SINCE_VERSION 1 + +/** @ingroup iface_empty */ +static inline void +empty_set_user_data(struct empty *empty, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) empty, user_data); +} + +/** @ingroup iface_empty */ +static inline void * +empty_get_user_data(struct empty *empty) +{ + return wl_proxy_get_user_data((struct wl_proxy *) empty); +} + +static inline uint32_t +empty_get_version(struct empty *empty) +{ + return wl_proxy_get_version((struct wl_proxy *) empty); +} + +/** @ingroup iface_empty */ +static inline void +empty_destroy(struct empty *empty) +{ + wl_proxy_destroy((struct wl_proxy *) empty); +} + +/** + * @ingroup iface_empty + */ +static inline void +empty_empty(struct empty *empty) +{ + wl_proxy_marshal_flags((struct wl_proxy *) empty, + EMPTY_EMPTY, NULL, wl_proxy_get_version((struct wl_proxy *) empty), 0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/empty-code.c b/tests/data/empty-code.c new file mode 100644 index 00000000..6f0f6190 --- /dev/null +++ b/tests/data/empty-code.c @@ -0,0 +1,20 @@ +/* SCANNER TEST */ + +#include +#include +#include "wayland-util.h" + + +static const struct wl_interface *empty_types[] = { +}; + +static const struct wl_message empty_requests[] = { + { "empty", "", empty_types + 0 }, +}; + +WL_EXPORT const struct wl_interface empty_interface = { + "empty", 1, + 1, empty_requests, + 0, NULL, +}; + diff --git a/tests/data/empty-server.h b/tests/data/empty-server.h new file mode 100644 index 00000000..4baf6d6b --- /dev/null +++ b/tests/data/empty-server.h @@ -0,0 +1,58 @@ +/* SCANNER TEST */ + +#ifndef EMPTY_SERVER_PROTOCOL_H +#define EMPTY_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_empty The empty protocol + * @section page_ifaces_empty Interfaces + * - @subpage page_iface_empty - + */ +struct empty; + +#ifndef EMPTY_INTERFACE +#define EMPTY_INTERFACE +/** + * @page page_iface_empty empty + * @section page_iface_empty_api API + * See @ref iface_empty. + */ +/** + * @defgroup iface_empty The empty interface + */ +extern const struct wl_interface empty_interface; +#endif + +/** + * @ingroup iface_empty + * @struct empty_interface + */ +struct empty_interface { + /** + */ + void (*empty)(struct wl_client *client, + struct wl_resource *resource); +}; + + +/** + * @ingroup iface_empty + */ +#define EMPTY_EMPTY_SINCE_VERSION 1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/data/empty.xml b/tests/data/empty.xml new file mode 100644 index 00000000..2549d8fc --- /dev/null +++ b/tests/data/empty.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/scanner-test-gen.sh b/tests/scanner-test-gen.sh index 5af1a727..cf4f79ff 100755 --- a/tests/scanner-test-gen.sh +++ b/tests/scanner-test-gen.sh @@ -19,3 +19,7 @@ generate "-c client-header" "small.xml" "small-client-core.h" generate "-c server-header" "small.xml" "small-server-core.h" generate "private-code" "small.xml" "small-private-code.c" + +generate "code" "empty.xml" "empty-code.c" +generate "client-header" "empty.xml" "empty-client.h" +generate "server-header" "empty.xml" "empty-server.h" diff --git a/tests/scanner-test.sh b/tests/scanner-test.sh index 35ba0473..4f4da7ab 100755 --- a/tests/scanner-test.sh +++ b/tests/scanner-test.sh @@ -67,6 +67,10 @@ generate_and_compare "code" "small.xml" "small-code.c" generate_and_compare "public-code" "small.xml" "small-code.c" generate_and_compare "private-code" "small.xml" "small-private-code.c" +generate_and_compare "code" "empty.xml" "empty-code.c" +generate_and_compare "client-header" "empty.xml" "empty-client.h" +generate_and_compare "server-header" "empty.xml" "empty-server.h" + verify_error "bad-identifier-arg.xml" "bad-identifier-arg.log" 7 verify_error "bad-identifier-entry.xml" "bad-identifier-entry.log" 8 verify_error "bad-identifier-enum.xml" "bad-identifier-enum.log" 6 From 2621484037869c917621b9f961310f13c09fcc00 Mon Sep 17 00:00:00 2001 From: Jordan Williams Date: Mon, 11 Mar 2024 09:06:55 -0500 Subject: [PATCH 0981/1152] egl: Disable symbols check for static builds The symbols check only works for dynamic libraries. When building statically, the test fails. This is caused by the check filtering out non-dynamic symbols with nm. This change skips the check when building only static libraries. Signed-off-by: Jordan Williams --- egl/meson.build | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/egl/meson.build b/egl/meson.build index 5c62ac1e..5363e808 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -13,16 +13,21 @@ if get_option('tests') wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c') test('wayland-egl abi check', wayland_egl_abi_check) - nm_path = find_program(['llvm-nm', 'nm']).full_path() - - test( - 'wayland-egl symbols check', - find_program('wayland-egl-symbols-check'), - env: [ - 'WAYLAND_EGL_LIB=@0@'.format(wayland_egl.full_path()), - 'NM=@0@'.format(nm_path) - ] - ) + if get_option('default_library') != 'static' + nm_path = find_program(['llvm-nm', 'nm']).full_path() + wayland_egl_shared = wayland_egl + if get_option('default_library') == 'both' + wayland_egl_shared = wayland_egl.get_shared_lib() + endif + test( + 'wayland-egl symbols check', + find_program('wayland-egl-symbols-check'), + env: [ + 'WAYLAND_EGL_LIB=@0@'.format(wayland_egl_shared.full_path()), + 'NM=@0@'.format(nm_path) + ] + ) + endif endif install_headers([ From fbd7460737c9cbae943bbc5d68a0fc6ca753c4d8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 May 2023 12:18:07 +0200 Subject: [PATCH 0982/1152] scanner: add new enum-header mode This generates a header with only enum definitions. This is useful to share enum headers between libraries and library users. Signed-off-by: Simon Ser --- src/scanner.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/scanner.c b/src/scanner.c index c512d231..3257cb61 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -67,7 +67,7 @@ enum visibility { static int usage(int ret) { - fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|private-code|public-code]" + fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|enum-header|private-code|public-code]" " [input_file output_file]\n", PROGRAM_NAME); fprintf(stderr, "\n"); fprintf(stderr, "Converts XML protocol descriptions supplied on " @@ -1703,6 +1703,35 @@ emit_header(struct protocol *protocol, enum side side) "#endif\n"); } +static void +emit_enum_header(struct protocol *protocol) +{ + struct interface *i, *i_next; + + printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); + + printf("#ifndef %s_ENUM_PROTOCOL_H\n" + "#define %s_ENUM_PROTOCOL_H\n" + "\n" + "#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif\n\n", + protocol->uppercase_name, + protocol->uppercase_name); + + wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) { + emit_enumerations(i); + + free_interface(i); + } + + printf("#ifdef __cplusplus\n" + "}\n" + "#endif\n" + "\n" + "#endif\n"); +} + static void emit_null_run(struct protocol *protocol) { @@ -1923,6 +1952,7 @@ int main(int argc, char *argv[]) enum { CLIENT_HEADER, SERVER_HEADER, + ENUM_HEADER, PRIVATE_CODE, PUBLIC_CODE, CODE, @@ -1976,6 +2006,8 @@ int main(int argc, char *argv[]) mode = CLIENT_HEADER; else if (strcmp(argv[0], "server-header") == 0) mode = SERVER_HEADER; + else if (strcmp(argv[0], "enum-header") == 0) + mode = ENUM_HEADER; else if (strcmp(argv[0], "private-code") == 0) mode = PRIVATE_CODE; else if (strcmp(argv[0], "public-code") == 0) @@ -2067,6 +2099,9 @@ int main(int argc, char *argv[]) case SERVER_HEADER: emit_header(&protocol, SERVER); break; + case ENUM_HEADER: + emit_enum_header(&protocol); + break; case PRIVATE_CODE: emit_code(&protocol, PRIVATE); break; From 2e0dbb7021f713924954c37537f7831791135c30 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 May 2023 16:52:55 +0200 Subject: [PATCH 0983/1152] tests: add scanner test for enum-header Signed-off-by: Simon Ser --- tests/data/example-enum.h | 836 ++++++++++++++++++++++++++++++++++++++ tests/scanner-test-gen.sh | 1 + tests/scanner-test.sh | 1 + 3 files changed, 838 insertions(+) create mode 100644 tests/data/example-enum.h diff --git a/tests/data/example-enum.h b/tests/data/example-enum.h new file mode 100644 index 00000000..9aec4035 --- /dev/null +++ b/tests/data/example-enum.h @@ -0,0 +1,836 @@ +/* SCANNER TEST */ + +#ifndef WAYLAND_ENUM_PROTOCOL_H +#define WAYLAND_ENUM_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WL_DISPLAY_ERROR_ENUM +#define WL_DISPLAY_ERROR_ENUM +/** + * @ingroup iface_wl_display + * global error values + * + * These errors are global and can be emitted in response to any + * server request. + */ +enum wl_display_error { + /** + * server couldn't find object + */ + WL_DISPLAY_ERROR_INVALID_OBJECT = 0, + /** + * method doesn't exist on the specified interface + */ + WL_DISPLAY_ERROR_INVALID_METHOD = 1, + /** + * server is out of memory + */ + WL_DISPLAY_ERROR_NO_MEMORY = 2, +}; +#endif /* WL_DISPLAY_ERROR_ENUM */ + +#ifndef WL_SHM_ERROR_ENUM +#define WL_SHM_ERROR_ENUM +/** + * @ingroup iface_wl_shm + * wl_shm error values + * + * These errors can be emitted in response to wl_shm requests. + */ +enum wl_shm_error { + /** + * buffer format is not known + */ + WL_SHM_ERROR_INVALID_FORMAT = 0, + /** + * invalid size or stride during pool or buffer creation + */ + WL_SHM_ERROR_INVALID_STRIDE = 1, + /** + * mmapping the file descriptor failed + */ + WL_SHM_ERROR_INVALID_FD = 2, +}; +#endif /* WL_SHM_ERROR_ENUM */ + +#ifndef WL_SHM_FORMAT_ENUM +#define WL_SHM_FORMAT_ENUM +/** + * @ingroup iface_wl_shm + * pixel formats + * + * This describes the memory layout of an individual pixel. + * + * All renderers should support argb8888 and xrgb8888 but any other + * formats are optional and may not be supported by the particular + * renderer in use. + * + * The drm format codes match the macros defined in drm_fourcc.h. + * The formats actually supported by the compositor will be + * reported by the format event. + */ +enum wl_shm_format { + /** + * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ARGB8888 = 0, + /** + * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XRGB8888 = 1, + /** + * 8-bit color index format, [7:0] C + */ + WL_SHM_FORMAT_C8 = 0x20203843, + /** + * 8-bit RGB format, [7:0] R:G:B 3:3:2 + */ + WL_SHM_FORMAT_RGB332 = 0x38424752, + /** + * 8-bit BGR format, [7:0] B:G:R 2:3:3 + */ + WL_SHM_FORMAT_BGR233 = 0x38524742, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XRGB4444 = 0x32315258, + /** + * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XBGR4444 = 0x32314258, + /** + * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBX4444 = 0x32315852, + /** + * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRX4444 = 0x32315842, + /** + * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ARGB4444 = 0x32315241, + /** + * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ABGR4444 = 0x32314241, + /** + * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBA4444 = 0x32314152, + /** + * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRA4444 = 0x32314142, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XRGB1555 = 0x35315258, + /** + * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XBGR1555 = 0x35314258, + /** + * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBX5551 = 0x35315852, + /** + * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRX5551 = 0x35315842, + /** + * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ARGB1555 = 0x35315241, + /** + * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ABGR1555 = 0x35314241, + /** + * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBA5551 = 0x35314152, + /** + * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRA5551 = 0x35314142, + /** + * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian + */ + WL_SHM_FORMAT_RGB565 = 0x36314752, + /** + * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian + */ + WL_SHM_FORMAT_BGR565 = 0x36314742, + /** + * 24-bit RGB format, [23:0] R:G:B little endian + */ + WL_SHM_FORMAT_RGB888 = 0x34324752, + /** + * 24-bit BGR format, [23:0] B:G:R little endian + */ + WL_SHM_FORMAT_BGR888 = 0x34324742, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XBGR8888 = 0x34324258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBX8888 = 0x34325852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRX8888 = 0x34325842, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ABGR8888 = 0x34324241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBA8888 = 0x34324152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRA8888 = 0x34324142, + /** + * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XRGB2101010 = 0x30335258, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XBGR2101010 = 0x30334258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBX1010102 = 0x30335852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRX1010102 = 0x30335842, + /** + * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ARGB2101010 = 0x30335241, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ABGR2101010 = 0x30334241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBA1010102 = 0x30334152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRA1010102 = 0x30334142, + /** + * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YUYV = 0x56595559, + /** + * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YVYU = 0x55595659, + /** + * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_UYVY = 0x59565955, + /** + * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_VYUY = 0x59555956, + /** + * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian + */ + WL_SHM_FORMAT_AYUV = 0x56555941, + /** + * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV12 = 0x3231564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV21 = 0x3132564e, + /** + * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV16 = 0x3631564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV61 = 0x3136564e, + /** + * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV410 = 0x39565559, + /** + * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU410 = 0x39555659, + /** + * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV411 = 0x31315559, + /** + * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU411 = 0x31315659, + /** + * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV420 = 0x32315559, + /** + * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU420 = 0x32315659, + /** + * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV422 = 0x36315559, + /** + * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU422 = 0x36315659, + /** + * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV444 = 0x34325559, + /** + * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU444 = 0x34325659, +}; +#endif /* WL_SHM_FORMAT_ENUM */ + +#ifndef WL_DATA_OFFER_ERROR_ENUM +#define WL_DATA_OFFER_ERROR_ENUM +enum wl_data_offer_error { + /** + * finish request was called untimely + */ + WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, + /** + * action mask contains invalid values + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, + /** + * action argument has an invalid value + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, + /** + * offer doesn't accept this request + */ + WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, +}; +#endif /* WL_DATA_OFFER_ERROR_ENUM */ + +#ifndef WL_DATA_SOURCE_ERROR_ENUM +#define WL_DATA_SOURCE_ERROR_ENUM +enum wl_data_source_error { + /** + * action mask contains invalid values + */ + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, + /** + * source doesn't accept this request + */ + WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, +}; +#endif /* WL_DATA_SOURCE_ERROR_ENUM */ + +#ifndef WL_DATA_DEVICE_ERROR_ENUM +#define WL_DATA_DEVICE_ERROR_ENUM +enum wl_data_device_error { + /** + * given wl_surface has another role + */ + WL_DATA_DEVICE_ERROR_ROLE = 0, +}; +#endif /* WL_DATA_DEVICE_ERROR_ENUM */ + +#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +/** + * @ingroup iface_wl_data_device_manager + * drag and drop actions + * + * This is a bitmask of the available/preferred actions in a + * drag-and-drop operation. + * + * In the compositor, the selected action is a result of matching the + * actions offered by the source and destination sides. "action" events + * with a "none" action will be sent to both source and destination if + * there is no match. All further checks will effectively happen on + * (source actions ∩ destination actions). + * + * In addition, compositors may also pick different actions in + * reaction to key modifiers being pressed. One common design that + * is used in major toolkits (and the behavior recommended for + * compositors) is: + * + * - If no modifiers are pressed, the first match (in bit order) + * will be used. + * - Pressing Shift selects "move", if enabled in the mask. + * - Pressing Control selects "copy", if enabled in the mask. + * + * Behavior beyond that is considered implementation-dependent. + * Compositors may for example bind other modifiers (like Alt/Meta) + * or drags initiated with other buttons than BTN_LEFT to specific + * actions (e.g. "ask"). + */ +enum wl_data_device_manager_dnd_action { + /** + * no action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, + /** + * copy action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, + /** + * move action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, + /** + * ask action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, +}; +#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ + +#ifndef WL_SHELL_ERROR_ENUM +#define WL_SHELL_ERROR_ENUM +enum wl_shell_error { + /** + * given wl_surface has another role + */ + WL_SHELL_ERROR_ROLE = 0, +}; +#endif /* WL_SHELL_ERROR_ENUM */ + +#ifndef WL_SHELL_SURFACE_RESIZE_ENUM +#define WL_SHELL_SURFACE_RESIZE_ENUM +/** + * @ingroup iface_wl_shell_surface + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. The server may + * use this information to adapt its behavior, e.g. choose + * an appropriate cursor image. + */ +enum wl_shell_surface_resize { + /** + * no edge + */ + WL_SHELL_SURFACE_RESIZE_NONE = 0, + /** + * top edge + */ + WL_SHELL_SURFACE_RESIZE_TOP = 1, + /** + * bottom edge + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, + /** + * left edge + */ + WL_SHELL_SURFACE_RESIZE_LEFT = 4, + /** + * top and left edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, + /** + * bottom and left edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, + /** + * right edge + */ + WL_SHELL_SURFACE_RESIZE_RIGHT = 8, + /** + * top and right edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, + /** + * bottom and right edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, +}; +#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ + +#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM +#define WL_SHELL_SURFACE_TRANSIENT_ENUM +/** + * @ingroup iface_wl_shell_surface + * details of transient behaviour + * + * These flags specify details of the expected behaviour + * of transient surfaces. Used in the set_transient request. + */ +enum wl_shell_surface_transient { + /** + * do not set keyboard focus + */ + WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, +}; +#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ + +#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +/** + * @ingroup iface_wl_shell_surface + * different method to set the surface fullscreen + * + * Hints to indicate to the compositor how to deal with a conflict + * between the dimensions of the surface and the dimensions of the + * output. The compositor is free to ignore this parameter. + */ +enum wl_shell_surface_fullscreen_method { + /** + * no preference, apply default policy + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, + /** + * scale, preserve the surface's aspect ratio and center on output + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, + /** + * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, + /** + * no upscaling, center on output and add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, +}; +#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ + +#ifndef WL_SURFACE_ERROR_ENUM +#define WL_SURFACE_ERROR_ENUM +/** + * @ingroup iface_wl_surface + * wl_surface error values + * + * These errors can be emitted in response to wl_surface requests. + */ +enum wl_surface_error { + /** + * buffer scale value is invalid + */ + WL_SURFACE_ERROR_INVALID_SCALE = 0, + /** + * buffer transform value is invalid + */ + WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, +}; +#endif /* WL_SURFACE_ERROR_ENUM */ + +#ifndef WL_SEAT_CAPABILITY_ENUM +#define WL_SEAT_CAPABILITY_ENUM +/** + * @ingroup iface_wl_seat + * seat capability bitmask + * + * This is a bitmask of capabilities this seat has; if a member is + * set, then it is present on the seat. + */ +enum wl_seat_capability { + /** + * the seat has pointer devices + */ + WL_SEAT_CAPABILITY_POINTER = 1, + /** + * the seat has one or more keyboards + */ + WL_SEAT_CAPABILITY_KEYBOARD = 2, + /** + * the seat has touch devices + */ + WL_SEAT_CAPABILITY_TOUCH = 4, +}; +#endif /* WL_SEAT_CAPABILITY_ENUM */ + +#ifndef WL_POINTER_ERROR_ENUM +#define WL_POINTER_ERROR_ENUM +enum wl_pointer_error { + /** + * given wl_surface has another role + */ + WL_POINTER_ERROR_ROLE = 0, +}; +#endif /* WL_POINTER_ERROR_ENUM */ + +#ifndef WL_POINTER_BUTTON_STATE_ENUM +#define WL_POINTER_BUTTON_STATE_ENUM +/** + * @ingroup iface_wl_pointer + * physical button state + * + * Describes the physical state of a button that produced the button + * event. + */ +enum wl_pointer_button_state { + /** + * the button is not pressed + */ + WL_POINTER_BUTTON_STATE_RELEASED = 0, + /** + * the button is pressed + */ + WL_POINTER_BUTTON_STATE_PRESSED = 1, +}; +#endif /* WL_POINTER_BUTTON_STATE_ENUM */ + +#ifndef WL_POINTER_AXIS_ENUM +#define WL_POINTER_AXIS_ENUM +/** + * @ingroup iface_wl_pointer + * axis types + * + * Describes the axis types of scroll events. + */ +enum wl_pointer_axis { + /** + * vertical axis + */ + WL_POINTER_AXIS_VERTICAL_SCROLL = 0, + /** + * horizontal axis + */ + WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, +}; +#endif /* WL_POINTER_AXIS_ENUM */ + +#ifndef WL_POINTER_AXIS_SOURCE_ENUM +#define WL_POINTER_AXIS_SOURCE_ENUM +/** + * @ingroup iface_wl_pointer + * axis source types + * + * Describes the source types for axis events. This indicates to the + * client how an axis event was physically generated; a client may + * adjust the user interface accordingly. For example, scroll events + * from a "finger" source may be in a smooth coordinate space with + * kinetic scrolling whereas a "wheel" source may be in discrete steps + * of a number of lines. + */ +enum wl_pointer_axis_source { + /** + * a physical wheel rotation + */ + WL_POINTER_AXIS_SOURCE_WHEEL = 0, + /** + * finger on a touch surface + */ + WL_POINTER_AXIS_SOURCE_FINGER = 1, + /** + * continuous coordinate space + * + * A device generating events in a continuous coordinate space, + * but using something other than a finger. One example for this + * source is button-based scrolling where the vertical motion of a + * device is converted to scroll events while a button is held + * down. + */ + WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, + /** + * a physical wheel tilt + * + * Indicates that the actual device is a wheel but the scroll + * event is not caused by a rotation but a (usually sideways) tilt + * of the wheel. + * @since 6 + */ + WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, +}; +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 +#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ + +#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM +#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM +/** + * @ingroup iface_wl_keyboard + * keyboard mapping format + * + * This specifies the format of the keymap provided to the + * client with the wl_keyboard.keymap event. + */ +enum wl_keyboard_keymap_format { + /** + * no keymap; client must understand how to interpret the raw keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, + /** + * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, +}; +#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ + +#ifndef WL_KEYBOARD_KEY_STATE_ENUM +#define WL_KEYBOARD_KEY_STATE_ENUM +/** + * @ingroup iface_wl_keyboard + * physical key state + * + * Describes the physical state of a key that produced the key event. + */ +enum wl_keyboard_key_state { + /** + * key is not pressed + */ + WL_KEYBOARD_KEY_STATE_RELEASED = 0, + /** + * key is pressed + */ + WL_KEYBOARD_KEY_STATE_PRESSED = 1, +}; +#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ + +#ifndef WL_OUTPUT_SUBPIXEL_ENUM +#define WL_OUTPUT_SUBPIXEL_ENUM +/** + * @ingroup iface_wl_output + * subpixel geometry information + * + * This enumeration describes how the physical + * pixels on an output are laid out. + */ +enum wl_output_subpixel { + /** + * unknown geometry + */ + WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, + /** + * no geometry + */ + WL_OUTPUT_SUBPIXEL_NONE = 1, + /** + * horizontal RGB + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, + /** + * horizontal BGR + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, + /** + * vertical RGB + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, + /** + * vertical BGR + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, +}; +#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ + +#ifndef WL_OUTPUT_TRANSFORM_ENUM +#define WL_OUTPUT_TRANSFORM_ENUM +/** + * @ingroup iface_wl_output + * transform from framebuffer to output + * + * This describes the transform that a compositor will apply to a + * surface to compensate for the rotation or mirroring of an + * output device. + * + * The flipped values correspond to an initial flip around a + * vertical axis followed by rotation. + * + * The purpose is mainly to allow clients to render accordingly and + * tell the compositor, so that for fullscreen surfaces, the + * compositor will still be able to scan out directly from client + * surfaces. + */ +enum wl_output_transform { + /** + * no transform + */ + WL_OUTPUT_TRANSFORM_NORMAL = 0, + /** + * 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_90 = 1, + /** + * 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_180 = 2, + /** + * 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_270 = 3, + /** + * 180 degree flip around a vertical axis + */ + WL_OUTPUT_TRANSFORM_FLIPPED = 4, + /** + * flip and rotate 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, + /** + * flip and rotate 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, + /** + * flip and rotate 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, +}; +#endif /* WL_OUTPUT_TRANSFORM_ENUM */ + +#ifndef WL_OUTPUT_MODE_ENUM +#define WL_OUTPUT_MODE_ENUM +/** + * @ingroup iface_wl_output + * mode information + * + * These flags describe properties of an output mode. + * They are used in the flags bitfield of the mode event. + */ +enum wl_output_mode { + /** + * indicates this is the current mode + */ + WL_OUTPUT_MODE_CURRENT = 0x1, + /** + * indicates this is the preferred mode + */ + WL_OUTPUT_MODE_PREFERRED = 0x2, +}; +#endif /* WL_OUTPUT_MODE_ENUM */ + +#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM +#define WL_SUBCOMPOSITOR_ERROR_ENUM +enum wl_subcompositor_error { + /** + * the to-be sub-surface is invalid + */ + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ + +#ifndef WL_SUBSURFACE_ERROR_ENUM +#define WL_SUBSURFACE_ERROR_ENUM +enum wl_subsurface_error { + /** + * wl_surface is not a sibling or the parent + */ + WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBSURFACE_ERROR_ENUM */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/scanner-test-gen.sh b/tests/scanner-test-gen.sh index cf4f79ff..b9c9294d 100755 --- a/tests/scanner-test-gen.sh +++ b/tests/scanner-test-gen.sh @@ -9,6 +9,7 @@ generate() { generate "code" "example.xml" "example-code.c" generate "client-header" "example.xml" "example-client.h" generate "server-header" "example.xml" "example-server.h" +generate "enum-header" "example.xml" "example-enum.h" generate "code" "small.xml" "small-code.c" generate "client-header" "small.xml" "small-client.h" diff --git a/tests/scanner-test.sh b/tests/scanner-test.sh index 4f4da7ab..d4cd19ba 100755 --- a/tests/scanner-test.sh +++ b/tests/scanner-test.sh @@ -53,6 +53,7 @@ verify_error() { generate_and_compare "code" "example.xml" "example-code.c" generate_and_compare "client-header" "example.xml" "example-client.h" generate_and_compare "server-header" "example.xml" "example-server.h" +generate_and_compare "enum-header" "example.xml" "example-enum.h" generate_and_compare "code" "small.xml" "small-code.c" generate_and_compare "client-header" "small.xml" "small-client.h" From 4945f2664fced2cb7b6d836169cfe6e87ee19b90 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 15 Mar 2024 18:02:44 +0100 Subject: [PATCH 0984/1152] wl_touch.cancel: document lack of frame event This appears to be what at least wlroots-based compositors and kwin do in practice. However, it's not abundantly clear from the protocol text what the expected behavior here is. This patch fixes that. Signed-off-by: Isaac Freund --- protocol/wayland.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d817a6e2..d1a75a7d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2625,6 +2625,8 @@ currently active on this client's surface. The client is responsible for finalizing the touch points, future touch points on this surface may reuse the touch point ID. + + No frame event is required after the cancel event. From 36cef8653fe57eff7d38fc0f4877bb900b1a21ea Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 Mar 2024 15:33:41 +0100 Subject: [PATCH 0985/1152] util: convert macros to inline functions Functionally equivalent except the usual macro footguns are avoided and type safety is increased. Signed-off-by: Simon Ser --- src/wayland-util.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index bb2a1838..7231346b 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -174,9 +174,23 @@ union map_entry { void *data; }; -#define map_entry_is_free(entry) ((entry).next & 0x1) -#define map_entry_get_data(entry) ((void *)((entry).next & ~(uintptr_t)0x3)) -#define map_entry_get_flags(entry) (((entry).next >> 1) & 0x1) +static inline bool +map_entry_is_free(union map_entry entry) +{ + return entry.next & 0x1; +} + +static inline void * +map_entry_get_data(union map_entry entry) +{ + return (void *)(entry.next & ~(uintptr_t)0x3); +} + +static inline uint32_t +map_entry_get_flags(union map_entry entry) +{ + return (entry.next >> 1) & 0x1; +} void wl_map_init(struct wl_map *map, uint32_t side) From d074d52902633d8700ce06b484508db0f8fba02b Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sat, 25 Sep 2021 22:34:44 -0400 Subject: [PATCH 0986/1152] connection: Dynamically resize connection buffers When using fixed size connection buffers, if either the client or the server is sending requests faster than the other end can cope with, the connection buffers will fill up, eventually killing the connection. This can be a problem for example with Xwayland mapping a lot of windows, faster than the Wayland compositor can cope with, or a high-rate mouse flooding the Wayland client with pointer events. To avoid the issue, resize the connection buffers dynamically when they get full. Both data and fd buffers are resized on demand. The default max buffer size is controlled via the wl_display interface while each client's connection buffer size is adjustable for finer control. The purpose is to explicitly have larger connection buffers for specific clients such as Xwayland, or set a larger buffer size for the client with pointer focus to deal with a higher input events rate. v0: Manuel: Dynamically resize connection buffers - Both data and fd buffers are resized on demand. v1: Olivier 1. Add support for unbounded buffers on the client side and growable (yet limited) connection buffers on the server side. 2. Add the API to set the default maximum size and a limit for a given client. 3. Add tests for growable connection buffers and adjustable limits. v2: Additional fixes by John: 1. Fix the size calculation in ring_buffer_check_space() 2. Fix wl_connection_read() to return gracefully once it has read up to the max buffer size, rather than returning an error. 3. If wl_connection_flush() fails with EAGAIN but the transmit ring-buffer has space remaining (or can be expanded), wl_connection_queue() should store the message rather than returning an error. 4. When the receive ring-buffer is at capacity but more data is available to be read, wl_connection_read() should attempt to expand the ring-buffer in order to read the remaining data. v3: Thomas Lukaszewicz Add a test for unbounded buffers v4: Add a client API as well to force bounded buffers (unbounded by default (Olivier) v5: Simplify ring_buffer_ensure_space() (Sebastian) Co-authored-by: Olivier Fourdan Co-authored-by: John Lindgren Co-authored-by: Sebastian Wick Signed-off-by: Manuel Stoeckl Signed-off-by: Olivier Fourdan Signed-off-by: John Lindgren Signed-off-by: Sebastian Wick Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237 --- src/connection.c | 353 +++++++++++++++++++++++++++++--------- src/wayland-client-core.h | 4 + src/wayland-client.c | 28 ++- src/wayland-private.h | 8 +- src/wayland-server-core.h | 7 + src/wayland-server.c | 65 ++++++- tests/connection-test.c | 67 +++++++- tests/display-test.c | 9 +- tests/os-wrappers-test.c | 6 +- 9 files changed, 460 insertions(+), 87 deletions(-) diff --git a/src/connection.c b/src/connection.c index a58b7a7c..8870fd2d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -26,6 +26,7 @@ #define _GNU_SOURCE +#include #include #include #include @@ -55,12 +56,12 @@ div_roundup(uint32_t n, size_t a) } struct wl_ring_buffer { - char data[4096]; - uint32_t head, tail; + char *data; + size_t head, tail; + uint32_t size_bits; + uint32_t max_size_bits; /* 0 for unlimited */ }; -#define MASK(i) ((i) & 4095) - #define MAX_FDS_OUT 28 #define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t))) @@ -71,26 +72,38 @@ struct wl_connection { int want_flush; }; +static inline size_t +size_pot(uint32_t size_bits) +{ + assert(size_bits < 8 * sizeof(size_t)); + + return ((size_t)1) << size_bits; +} + +static size_t +ring_buffer_capacity(const struct wl_ring_buffer *b) { + return size_pot(b->size_bits); +} + +static size_t +ring_buffer_mask(const struct wl_ring_buffer *b, size_t i) { + size_t m = ring_buffer_capacity(b) - 1; + return i & m; +} + static int ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count) { - uint32_t head, size; - - if (count > sizeof(b->data)) { - wl_log("Data too big for buffer (%d > %d).\n", - count, sizeof(b->data)); - errno = E2BIG; - return -1; - } + size_t head, size; if (count == 0) return 0; - head = MASK(b->head); - if (head + count <= sizeof b->data) { + head = ring_buffer_mask(b, b->head); + if (head + count <= ring_buffer_capacity(b)) { memcpy(b->data + head, data, count); } else { - size = sizeof b->data - head; + size = ring_buffer_capacity(b) - head; memcpy(b->data + head, data, size); memcpy(b->data, (const char *) data + size, count - size); } @@ -103,21 +116,21 @@ ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count) static void ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) { - uint32_t head, tail; + size_t head, tail; - head = MASK(b->head); - tail = MASK(b->tail); + head = ring_buffer_mask(b, b->head); + tail = ring_buffer_mask(b, b->tail); if (head < tail) { iov[0].iov_base = b->data + head; iov[0].iov_len = tail - head; *count = 1; } else if (tail == 0) { iov[0].iov_base = b->data + head; - iov[0].iov_len = sizeof b->data - head; + iov[0].iov_len = ring_buffer_capacity(b) - head; *count = 1; } else { iov[0].iov_base = b->data + head; - iov[0].iov_len = sizeof b->data - head; + iov[0].iov_len = ring_buffer_capacity(b) - head; iov[1].iov_base = b->data; iov[1].iov_len = tail; *count = 2; @@ -127,21 +140,21 @@ ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) static void ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) { - uint32_t head, tail; + size_t head, tail; - head = MASK(b->head); - tail = MASK(b->tail); + head = ring_buffer_mask(b, b->head); + tail = ring_buffer_mask(b, b->tail); if (tail < head) { iov[0].iov_base = b->data + tail; iov[0].iov_len = head - tail; *count = 1; } else if (head == 0) { iov[0].iov_base = b->data + tail; - iov[0].iov_len = sizeof b->data - tail; + iov[0].iov_len = ring_buffer_capacity(b) - tail; *count = 1; } else { iov[0].iov_base = b->data + tail; - iov[0].iov_len = sizeof b->data - tail; + iov[0].iov_len = ring_buffer_capacity(b) - tail; iov[1].iov_base = b->data; iov[1].iov_len = head; *count = 2; @@ -151,29 +164,158 @@ ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) static void ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count) { - uint32_t tail, size; + size_t tail, size; if (count == 0) return; - tail = MASK(b->tail); - if (tail + count <= sizeof b->data) { + tail = ring_buffer_mask(b, b->tail); + if (tail + count <= ring_buffer_capacity(b)) { memcpy(data, b->data + tail, count); } else { - size = sizeof b->data - tail; + size = ring_buffer_capacity(b) - tail; memcpy(data, b->data + tail, size); memcpy((char *) data + size, b->data, count - size); } } -static uint32_t +static size_t ring_buffer_size(struct wl_ring_buffer *b) { return b->head - b->tail; } +static char * +ring_buffer_tail(const struct wl_ring_buffer *b) +{ + return b->data + ring_buffer_mask(b, b->tail); +} + +static uint32_t +get_max_size_bits_for_size(size_t buffer_size) +{ + uint32_t max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT; + + /* buffer_size == 0 means unbound buffer size */ + if (buffer_size == 0) + return 0; + + while (max_size_bits < 8 * sizeof(size_t) && size_pot(max_size_bits) < buffer_size) + max_size_bits++; + + return max_size_bits; +} + +static int +ring_buffer_allocate(struct wl_ring_buffer *b, size_t size_bits) +{ + char *new_data; + + new_data = calloc(size_pot(size_bits), 1); + if (!new_data) + return -1; + + ring_buffer_copy(b, new_data, ring_buffer_size(b)); + free(b->data); + b->data = new_data; + b->size_bits = size_bits; + b->head = ring_buffer_size(b); + b->tail = 0; + + return 0; +} + +static size_t +ring_buffer_get_bits_for_size(struct wl_ring_buffer *b, size_t net_size) +{ + size_t max_size_bits = get_max_size_bits_for_size(net_size); + + if (max_size_bits < WL_BUFFER_DEFAULT_SIZE_POT) + max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT; + + if (b->max_size_bits > 0 && max_size_bits > b->max_size_bits) + max_size_bits = b->max_size_bits; + + return max_size_bits; +} + +static bool +ring_buffer_is_max_size_reached(struct wl_ring_buffer *b) +{ + size_t net_size = ring_buffer_size(b) + 1; + size_t size_bits = ring_buffer_get_bits_for_size(b, net_size); + + return net_size >= size_pot(size_bits); +} + +static int +ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count) +{ + size_t net_size = ring_buffer_size(b) + count; + size_t size_bits = ring_buffer_get_bits_for_size(b, net_size); + + /* The 'size_bits' value represents the required size (in POT) to store + * 'net_size', which depending whether the buffers are bounded or not + * might not be sufficient (i.e. we might have reached the maximum size + * allowed). + */ + if (net_size > size_pot(size_bits)) { + wl_log("Data too big for buffer (%d + %zd > %zd).\n", + ring_buffer_size(b), count, size_pot(size_bits)); + errno = E2BIG; + return -1; + } + + /* The following test here is a short-cut to avoid reallocating a buffer + * of the same size. + */ + if (size_bits == b->size_bits) + return 0; + + /* Otherwise, we (re)allocate the buffer to match the required size */ + return ring_buffer_allocate(b, size_bits); +} + +static void +ring_buffer_close_fds(struct wl_ring_buffer *buffer, int32_t count) +{ + int32_t i, *p; + size_t size, tail; + + size = ring_buffer_capacity(buffer); + tail = ring_buffer_mask(buffer, buffer->tail); + p = (int32_t *) (buffer->data + tail); + + for (i = 0; i < count; i++) { + if (p >= (int32_t *) (buffer->data + size)) + p = (int32_t *) buffer->data; + close(*p++); + } +} + +void +wl_connection_set_max_buffer_size(struct wl_connection *connection, + size_t max_buffer_size) +{ + uint32_t max_size_bits; + + max_size_bits = get_max_size_bits_for_size(max_buffer_size); + + connection->fds_in.max_size_bits = max_size_bits; + ring_buffer_ensure_space(&connection->fds_in, 0); + + connection->fds_out.max_size_bits = max_size_bits; + ring_buffer_ensure_space(&connection->fds_out, 0); + + connection->in.max_size_bits = max_size_bits; + ring_buffer_ensure_space(&connection->in, 0); + + connection->out.max_size_bits = max_size_bits; + ring_buffer_ensure_space(&connection->out, 0); +} + struct wl_connection * -wl_connection_create(int fd) +wl_connection_create(int fd, size_t max_buffer_size) { struct wl_connection *connection; @@ -181,6 +323,8 @@ wl_connection_create(int fd) if (connection == NULL) return NULL; + wl_connection_set_max_buffer_size(connection, max_buffer_size); + connection->fd = fd; return connection; @@ -189,20 +333,20 @@ wl_connection_create(int fd) static void close_fds(struct wl_ring_buffer *buffer, int max) { - int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count; size_t size; + int32_t count; size = ring_buffer_size(buffer); if (size == 0) return; - ring_buffer_copy(buffer, fds, size); - count = size / sizeof fds[0]; + count = size / sizeof(int32_t); if (max > 0 && max < count) count = max; - size = count * sizeof fds[0]; - for (i = 0; i < count; i++) - close(fds[i]); + + ring_buffer_close_fds(buffer, count); + + size = count * sizeof(int32_t); buffer->tail += size; } @@ -218,7 +362,13 @@ wl_connection_destroy(struct wl_connection *connection) int fd = connection->fd; close_fds(&connection->fds_out, -1); + free(connection->fds_out.data); + free(connection->out.data); + close_fds(&connection->fds_in, -1); + free(connection->fds_in.data); + free(connection->in.data); + free(connection); return fd; @@ -262,7 +412,7 @@ static int decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg) { struct cmsghdr *cmsg; - size_t size, max, i; + size_t size, i; int overflow = 0; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; @@ -272,8 +422,8 @@ decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg) continue; size = cmsg->cmsg_len - CMSG_LEN(0); - max = sizeof(buffer->data) - ring_buffer_size(buffer); - if (size > max || overflow) { + + if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) { overflow = 1; size /= sizeof(int32_t); for (i = 0; i < size; i++) @@ -299,17 +449,40 @@ wl_connection_flush(struct wl_connection *connection) char cmsg[CLEN]; int len = 0, count; size_t clen; - uint32_t tail; + size_t tail; if (!connection->want_flush) return 0; tail = connection->out.tail; - while (connection->out.head - connection->out.tail > 0) { - ring_buffer_get_iov(&connection->out, iov, &count); - + while (ring_buffer_size(&connection->out) > 0) { build_cmsg(&connection->fds_out, cmsg, &clen); + if (clen >= CLEN) { + /* UNIX domain sockets allows to send file descriptors + * using ancillary data. + * + * As per the UNIX domain sockets man page (man 7 unix), + * "at least one byte of real data should be sent when + * sending ancillary data". + * + * This is why we send only a single byte here, to ensure + * all file descriptors are sent before the bytes are + * cleared out. + * + * Otherwise This can fail to clear the file descriptors + * first if individual messages are allowed to have 224 + * (8 bytes * MAX_FDS_OUT = 224) file descriptors . + */ + iov[0].iov_base = ring_buffer_tail(&connection->out); + iov[0].iov_len = 1; + count = 1; + } else { + ring_buffer_get_iov(&connection->out, iov, &count); + } + + msg.msg_name = NULL; + msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; msg.msg_control = (clen > 0) ? cmsg : NULL; @@ -347,35 +520,48 @@ wl_connection_read(struct wl_connection *connection) char cmsg[CLEN]; int len, count, ret; - if (ring_buffer_size(&connection->in) >= sizeof(connection->in.data)) { - errno = EOVERFLOW; - return -1; + while (1) { + int data_size = ring_buffer_size(&connection->in); + + /* Stop once we've read the max buffer size. */ + if (ring_buffer_is_max_size_reached(&connection->in)) + return data_size; + + if (ring_buffer_ensure_space(&connection->in, 1) < 0) + return -1; + + ring_buffer_put_iov(&connection->in, iov, &count); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = count; + msg.msg_control = cmsg; + msg.msg_controllen = sizeof cmsg; + msg.msg_flags = 0; + + do { + len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT); + } while (len < 0 && errno == EINTR); + + if (len == 0) { + /* EOF, return previously read data first */ + return data_size; + } + if (len < 0) { + if (errno == EAGAIN && data_size > 0) { + /* nothing new read, return previously read data */ + return data_size; + } + return len; + } + + ret = decode_cmsg(&connection->fds_in, &msg); + if (ret) + return -1; + + connection->in.head += len; } - - ring_buffer_put_iov(&connection->in, iov, &count); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = count; - msg.msg_control = cmsg; - msg.msg_controllen = sizeof cmsg; - msg.msg_flags = 0; - - do { - len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT); - } while (len < 0 && errno == EINTR); - - if (len <= 0) - return len; - - ret = decode_cmsg(&connection->fds_in, &msg); - if (ret) - return -1; - - connection->in.head += len; - - return wl_connection_pending_input(connection); } int @@ -394,13 +580,23 @@ int wl_connection_queue(struct wl_connection *connection, const void *data, size_t count) { - if (connection->out.head - connection->out.tail + - count > ARRAY_LENGTH(connection->out.data)) { + /* We want to try to flush when the buffer reaches the default maximum + * size even if the buffer has been previously expanded. + * + * Otherwise the larger buffer will cause us to flush less frequently, + * which could increase lag. + * + * We'd like to flush often and get the buffer size back down if possible. + */ + if (ring_buffer_size(&connection->out) + count > WL_BUFFER_DEFAULT_MAX_SIZE) { connection->want_flush = 1; - if (wl_connection_flush(connection) < 0) + if (wl_connection_flush(connection) < 0 && errno != EAGAIN) return -1; } + if (ring_buffer_ensure_space(&connection->out, count) < 0) + return -1; + return ring_buffer_put(&connection->out, data, count); } @@ -426,12 +622,15 @@ wl_connection_get_fd(struct wl_connection *connection) static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { - if (ring_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) { + if (ring_buffer_size(&connection->fds_out) >= MAX_FDS_OUT * sizeof fd) { connection->want_flush = 1; - if (wl_connection_flush(connection) < 0) + if (wl_connection_flush(connection) < 0 && errno != EAGAIN) return -1; } + if (ring_buffer_ensure_space(&connection->fds_out, sizeof fd) < 0) + return -1; + return ring_buffer_put(&connection->fds_out, &fd, sizeof fd); } diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 20b2a3b2..a9d620e3 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -298,6 +298,10 @@ wl_display_read_events(struct wl_display *display); void wl_log_set_handler_client(wl_log_func_t handler); +void +wl_display_set_max_buffer_size(struct wl_display *display, + size_t max_buffer_size); + #ifdef __cplusplus } #endif diff --git a/src/wayland-client.c b/src/wayland-client.c index 665fe552..75fad4ff 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1269,7 +1269,7 @@ wl_display_connect_to_fd(int fd) */ display->proxy.version = 0; - display->connection = wl_connection_create(display->fd); + display->connection = wl_connection_create(display->fd, 0); if (display->connection == NULL) goto err_connection; @@ -2238,6 +2238,32 @@ wl_display_flush(struct wl_display *display) return ret; } +/** Adjust the maximum size of the client connection buffers + * + * \param display The display context object + * \param max_buffer_size The maximum size of the connection buffers + * + * Client buffers are unbounded by default. This function sets a limit to the + * size of the connection buffers. + * + * A value of 0 for \a max_buffer_size requests the buffers to be unbounded. + * + * The actual size of the connection buffers is a power of two, the requested + * \a max_buffer_size is therefore rounded up to the nearest power of two value. + * + * Lowering the maximum size may not take effect immediately if the current + * content of the buffer does not fit within the new size limit. + * + * \memberof wl_display + * \since 1.22.90 + */ +WL_EXPORT void +wl_display_set_max_buffer_size(struct wl_display *display, + size_t max_buffer_size) +{ + wl_connection_set_max_buffer_size(display->connection, max_buffer_size); +} + /** Set the user data associated with a proxy * * \param proxy The proxy object diff --git a/src/wayland-private.h b/src/wayland-private.h index a370763d..fe9120af 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -47,6 +47,8 @@ #define WL_SERVER_ID_START 0xff000000 #define WL_MAP_MAX_OBJECTS 0x00f00000 #define WL_CLOSURE_MAX_ARGS 20 +#define WL_BUFFER_DEFAULT_SIZE_POT 12 +#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT) /** * Argument types used in signatures. @@ -120,7 +122,7 @@ void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data); struct wl_connection * -wl_connection_create(int fd); +wl_connection_create(int fd, size_t max_buffer_size); int wl_connection_destroy(struct wl_connection *connection); @@ -252,4 +254,8 @@ zalloc(size_t s) void wl_connection_close_fds_in(struct wl_connection *connection, int max); +void +wl_connection_set_max_buffer_size(struct wl_connection *connection, + size_t max_buffer_size); + #endif diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 00a54433..63d0f02d 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -217,6 +217,10 @@ wl_display_flush_clients(struct wl_display *display); void wl_display_destroy_clients(struct wl_display *display); +void +wl_display_set_default_max_buffer_size(struct wl_display *display, + size_t max_buffer_size); + struct wl_client; typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, @@ -375,6 +379,9 @@ wl_client_set_user_data(struct wl_client *client, void * wl_client_get_user_data(struct wl_client *client); +void +wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size); + /** \class wl_listener * * \brief A single listener for Wayland signals diff --git a/src/wayland-server.c b/src/wayland-server.c index 9726807e..2df2e6ad 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -112,6 +112,8 @@ struct wl_display { int terminate_efd; struct wl_event_source *term_source; + + size_t max_buffer_size; }; struct wl_global { @@ -542,7 +544,8 @@ wl_client_create(struct wl_display *display, int fd) &client->pid) != 0) goto err_source; - client->connection = wl_connection_create(fd); + client->connection = wl_connection_create(fd, display->max_buffer_size); + if (client->connection == NULL) goto err_source; @@ -1172,6 +1175,7 @@ wl_display_create(void) display->global_filter = NULL; display->global_filter_data = NULL; + display->max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE; wl_array_init(&display->additional_shm_formats); @@ -1580,6 +1584,37 @@ wl_display_destroy_clients(struct wl_display *display) } } +/** Sets the default maximum size for connection buffers of new clients + * + * \param display The display object + * \param max_buffer_size The default maximum size of the connection buffers + * + * This function sets the default size of the internal connection buffers for + * new clients. It doesn't change the buffer size for existing wl_client. + * + * The connection buffer size of an existing wl_client can be adjusted using + * wl_client_set_max_buffer_size(). + * + * The actual size of the connection buffers is a power of two, the requested + * \a max_buffer_size is therefore rounded up to the nearest power of two value. + * + * The minimum buffer size is 4096. + * + * \sa wl_client_set_max_buffer_size + * + * \memberof wl_display + * \since 1.22.90 + */ +WL_EXPORT void +wl_display_set_default_max_buffer_size(struct wl_display *display, + size_t max_buffer_size) +{ + if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE) + max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE; + + display->max_buffer_size = max_buffer_size; +} + static int socket_data(int fd, uint32_t mask, void *data) { @@ -2275,6 +2310,34 @@ wl_signal_emit_mutable(struct wl_signal *signal, void *data) wl_list_remove(&end.link); } +/** Adjust the maximum size of the client connection buffers + * + * \param client The client object + * \param max_buffer_size The maximum size of the connection buffers + * + * The actual size of the connection buffers is a power of two, the requested + * \a max_buffer_size is therefore rounded up to the nearest power of two value. + * + * Lowering the maximum size may not take effect immediately if the current content + * of the buffer does not fit within the new size limit. + * + * The minimum buffer size is 4096. The default buffers size can be set using + * wl_display_set_default_max_buffer_size(). + * + * \sa wl_display_set_default_max_buffer_size() + * + * \memberof wl_client + * \since 1.22.90 + */ +WL_EXPORT void +wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size) +{ + if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE) + max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE; + + wl_connection_set_max_buffer_size(client->connection, max_buffer_size); +} + /** \cond INTERNAL */ /** Initialize a wl_priv_signal object diff --git a/tests/connection-test.c b/tests/connection-test.c index 9762e0da..dde5d89c 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -50,7 +50,7 @@ setup(int *s) assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); - connection = wl_connection_create(s[0]); + connection = wl_connection_create(s[0], WL_BUFFER_DEFAULT_MAX_SIZE); assert(connection); return connection; @@ -183,9 +183,11 @@ setup_marshal_data(struct marshal_data *data) { assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0); - data->read_connection = wl_connection_create(data->s[0]); + data->read_connection = wl_connection_create(data->s[0], + WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->read_connection); - data->write_connection = wl_connection_create(data->s[1]); + data->write_connection = wl_connection_create(data->s[1], + WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->write_connection); } @@ -277,6 +279,25 @@ expected_fail_marshal(int expected_error, const char *format, ...) assert(errno == expected_error); } +static void +marshal_send(struct marshal_data *data, const char *format, ...) +{ + struct wl_closure *closure; + static const uint32_t opcode = 4444; + static struct wl_object sender = { NULL, NULL, 1234 }; + struct wl_message message = { "test", format, NULL }; + va_list ap; + + va_start(ap, format); + closure = wl_closure_vmarshal(&sender, opcode, ap, &message); + va_end(ap); + + assert(closure); + assert(wl_closure_send(closure, data->write_connection) == 0); + + wl_closure_destroy(closure); +} + static void expected_fail_marshal_send(struct marshal_data *data, int expected_error, const char *format, ...) @@ -644,6 +665,46 @@ TEST(connection_marshal_too_big) free(big_string); } +TEST(connection_marshal_big_enough) +{ + struct marshal_data data; + char *big_string = malloc(5000); + + assert(big_string); + + memset(big_string, ' ', 4999); + big_string[4999] = '\0'; + + setup_marshal_data(&data); + wl_connection_set_max_buffer_size(data.write_connection, 5120); + + marshal_send(&data, "s", big_string); + + release_marshal_data(&data); + free(big_string); +} + +TEST(connection_marshal_unbounded_boundary_size) +{ + /* A string of lenth 8178 requires a buffer size of exactly 2^13. */ + struct marshal_data data; + char *big_string = malloc(8178); + assert(big_string); + + memset(big_string, ' ', 8177); + big_string[8177] = '\0'; + + setup_marshal_data(&data); + + /* Set the max size to 0 (unbounded). */ + wl_connection_set_max_buffer_size(data.write_connection, 0); + + marshal_send(&data, "s", big_string); + + release_marshal_data(&data); + free(big_string); +} + static void marshal_helper(const char *format, void *handler, ...) { diff --git a/tests/display-test.c b/tests/display-test.c index bcb3267f..c2def444 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1492,6 +1492,10 @@ send_overflow_client(void *data) char tmp = '\0'; int sock, optval = 16384; + /* By default, client buffers are now unbounded, set a limit to cause + * an overflow, otherwise the client buffers will grow indefinitely. */ + wl_display_set_max_buffer_size(c->wl_display, 4096); + /* Limit the send buffer size for the display socket to guarantee * that the test will cause an overflow. */ sock = wl_display_get_fd(c->wl_display); @@ -1505,6 +1509,7 @@ send_overflow_client(void *data) * within <=4096 iterations. */ for (i = 0; i < 1000000; i++) { noop_request(c); + fprintf(stderr, "Send loop %i\n", i); err = wl_display_get_error(c->wl_display); if (err) break; @@ -1514,9 +1519,9 @@ send_overflow_client(void *data) * check verifies that the initial/final FD counts are the same */ assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp)); - /* Expect an error */ + /* Expect an error - ring_buffer_ensure_space() returns E2BIG */ fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err)); - assert(err == EAGAIN); + assert(err == EAGAIN || err == E2BIG); client_disconnect_nocheck(c); } diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 23ddced8..061d29e6 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -235,10 +235,12 @@ setup_marshal_data(struct marshal_data *data) assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0); - data->read_connection = wl_connection_create(data->s[0]); + data->read_connection = wl_connection_create(data->s[0], + WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->read_connection); - data->write_connection = wl_connection_create(data->s[1]); + data->write_connection = wl_connection_create(data->s[1], + WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->write_connection); } From ad4ed17335e62d0187362dcfe9d70dac886a8065 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 Mar 2024 15:45:45 +0100 Subject: [PATCH 0987/1152] ci: bump Meson version to 0.57 Signed-off-by: Simon Ser --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2ac971a1..356181bb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -72,10 +72,10 @@ stages: BUILD_OS: debian FDO_DISTRIBUTION_VERSION: bookworm FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' - FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson==0.56.0' + FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson~=0.57.2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2023-08-02.0" + FDO_DISTRIBUTION_TAG: "2024-03-28.2" .debian-x86_64: extends: From e7df1f2af2ccc80a85d28b6b4064c6466e425bd0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 Mar 2024 15:40:44 +0100 Subject: [PATCH 0988/1152] build: bump minimum Meson version to 0.57 Fixes the following warning: tests/meson.build:91: WARNING: Project targets '>= 0.56.0' but uses feature introduced in '0.57.0': env arg in run_target. Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 431ebb7e..f6f7dd84 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'wayland', 'c', version: '1.22.90', license: 'MIT', - meson_version: '>= 0.56.0', + meson_version: '>= 0.57.0', default_options: [ 'warning_level=2', 'buildtype=debugoptimized', From 37699a98b1ebdc488a880b41b4b712403293d5d7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 Mar 2024 15:38:24 +0100 Subject: [PATCH 0989/1152] ci: use --fatal-meson-warnings Turns Meson warnings into errors. Useful to avoid missing warnings. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 356181bb..fd47a4b9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -217,7 +217,7 @@ armv7-debian-container_prep: stage: "Build and test" script: - cd "$BUILDDIR" - - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons -Dwerror=true ${MESON_BUILD_TYPE} .. + - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} .. - ninja -k0 -j${FDO_CI_CONCURRENT:-4} - meson test --num-processes ${FDO_CI_CONCURRENT:-4} - ninja clean @@ -306,7 +306,7 @@ armv7-release-debian-build: FDO_DISTRIBUTION_TAG: "2023-08-02.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. - MESON_ARGS: "-Ddocumentation=false" + MESON_ARGS: "--fatal-meson-warnings -Ddocumentation=false" .freebsd-x86_64: extends: From c5d145a602581ee70f3ee87566ccb5cf1ff6cce8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 Mar 2024 15:40:05 +0100 Subject: [PATCH 0990/1152] ci: turn on -Dwerror=true for FreeBSD It was turned on for Linux only. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fd47a4b9..7dc7e33f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -306,7 +306,7 @@ armv7-release-debian-build: FDO_DISTRIBUTION_TAG: "2023-08-02.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. - MESON_ARGS: "--fatal-meson-warnings -Ddocumentation=false" + MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false" .freebsd-x86_64: extends: From 03e304544b9b01c175813215f5930a07152be448 Mon Sep 17 00:00:00 2001 From: 6t8k <6t8k@noreply.codeberg.org> Date: Sat, 14 Oct 2023 23:25:48 +0200 Subject: [PATCH 0991/1152] cursor: memfd_create: try MFD_NOEXEC_SEAL Effective from Linux 6.3 onward, this creates the memfd without execute permissions and prevents that setting from ever being changed. A run-time fallback is made to not using MFD_NOEXEC_SEAL when a libwayland-cursor compiled on Linux >= 6.3 is run on Linux < 6.3. This is a defense-in-depth security measure and silences a respective kernel warning; see: https://lwn.net/Articles/918106/ This implementation is adopted from dnkl's `foot` terminal emulator. Signed-off-by: 6t8k <6t8k@noreply.codeberg.org> --- cursor/os-compatibility.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index f2445ced..2b54bae2 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -40,6 +40,11 @@ #include #endif +/* Fallback to no flag when missing the definition */ +#ifndef MFD_NOEXEC_SEAL +#define MFD_NOEXEC_SEAL 0 +#endif + #include "os-compatibility.h" #ifndef HAVE_MKOSTEMP @@ -124,7 +129,21 @@ os_create_anonymous_file(off_t size) int fd; #ifdef HAVE_MEMFD_CREATE - fd = memfd_create("wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING); + /* + * Linux kernels older than 6.3 reject MFD_NOEXEC_SEAL with EINVAL. + * Try first *with* it, and if that fails, try again *without* it. + */ + errno = 0; + fd = memfd_create( + "wayland-cursor", + MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); + + if (fd < 0 && errno == EINVAL && MFD_NOEXEC_SEAL != 0) { + fd = memfd_create( + "wayland-cursor", + MFD_CLOEXEC | MFD_ALLOW_SEALING); + } + if (fd >= 0) { /* We can add this seal before calling posix_fallocate(), as * the file is currently zero-sized anyway. From af1dc3ef4bbbc62675a68ff524edd577f2a56ece Mon Sep 17 00:00:00 2001 From: Colin Kinloch Date: Mon, 15 Apr 2024 11:47:11 +0100 Subject: [PATCH 0992/1152] protocol: Undefine wl_display_sync callback data Signed-off-by: Colin Kinloch --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index d1a75a7d..bde7d008 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -46,7 +46,7 @@ compositor after the callback is fired and as such the client must not attempt to use it after that point. - The callback_data passed in the callback is the event serial. + The callback_data passed in the callback is undefined and should be ignored. From 5eeaac6e1114fddeb36682ef1eead967c06e9b02 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 27 Feb 2024 14:21:05 +0100 Subject: [PATCH 0993/1152] Clarify behavior of buffer transformations The new text describes how - Mutter - Plasma - Sway 1.8 - Jay behave. Sway 1.9 flipped the behavior of 90 degree and 270 degree set_buffer_transform requests. [mpv] also changed the behavior of its vo_wayland_dmabuf backend which makes it only work correctly on sway 1.9. [mpv]: https://github.com/mpv-player/mpv/pull/12509 It seems that the previous text was open to interpretation or at least caused some amount of confusion. Signed-off-by: Julian Orth --- protocol/wayland.xml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index bde7d008..4c376160 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1704,10 +1704,12 @@ - This request sets an optional transformation on how the compositor - interprets the contents of the buffer attached to the surface. The - accepted values for the transform parameter are the values for - wl_output.transform. + This request sets the transformation that the client has already applied + to the content of the buffer. The accepted values for the transform + parameter are the values for wl_output.transform. + + The compositor applies the inverse of this transformation whenever it + uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. @@ -1861,9 +1863,9 @@ Before receiving this event the preferred buffer transform for this surface is normal. - It is intended that transform aware clients use this event to apply the - transform to their content and use wl_surface.set_buffer_transform to - indicate the transform they have rendered with. + Applying this transformation to the surface buffer contents and using + wl_surface.set_buffer_transform might allow the compositor to use the + surface buffer more efficiently. @@ -2726,10 +2728,9 @@ - - This describes the transform that a compositor will apply to a - surface to compensate for the rotation or mirroring of an - output device. + + This describes transformations that clients and compositors apply to + buffer contents. The flipped values correspond to an initial flip around a vertical axis followed by rotation. @@ -2787,7 +2788,7 @@ + summary="additional transformation applied to buffer contents during presentation"/> From b258d5f36137088e5cb5ae097db7964290da7d55 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 17 Sep 2022 10:53:56 +0200 Subject: [PATCH 0994/1152] scanner: add validators for enums Right now compositors need to manually check that enum values sent by the client are valid. In particular: - Check that the value sent by the client is not outside of the enum. - Check that the version of the enum entry is consistent with the object version. Automatically generate validator functions to perform these tasks. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/104 --- src/scanner.c | 36 +- tests/data/empty-code.c | 1 + tests/data/example-code.c | 1 + tests/data/example-server.h | 588 ++++++++++++++++++++++++++++++++ tests/data/small-client-core.h | 9 + tests/data/small-client.h | 9 + tests/data/small-code-core.c | 1 + tests/data/small-code.c | 1 + tests/data/small-private-code.c | 1 + tests/data/small-server-core.h | 31 ++ tests/data/small-server.h | 31 ++ tests/data/small.xml | 1 + tests/enum-validator-test.c | 13 + tests/meson.build | 1 + 14 files changed, 720 insertions(+), 4 deletions(-) create mode 100644 tests/enum-validator-test.c diff --git a/src/scanner.c b/src/scanner.c index 3257cb61..3f528f31 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1344,7 +1344,7 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface) } static void -emit_enumerations(struct interface *interface) +emit_enumerations(struct interface *interface, bool with_validators) { struct enumeration *e; struct entry *entry; @@ -1401,6 +1401,33 @@ emit_enumerations(struct interface *interface) } + if (with_validators) { + printf("/**\n" + " * @ingroup iface_%s\n" + " * Validate a %s %s value.\n" + " *\n" + " * @return true on success, false on error.\n" + " * @ref %s_%s\n" + " */\n" + "static inline bool\n" + "%s_%s_is_valid(uint32_t value, uint32_t version) {\n" + " switch (value) {\n", + interface->name, interface->name, e->name, + interface->name, e->name, + interface->name, e->name); + wl_list_for_each(entry, &e->entry_list, link) { + printf(" case %s%s_%s_%s:\n" + " return version >= %d;\n", + entry->value[0] == '-' ? "(uint32_t)" : "", + interface->uppercase_name, e->uppercase_name, + entry->uppercase_name, entry->since); + } + printf(" default:\n" + " return false;\n" + " }\n" + "}\n"); + } + printf("#endif /* %s_%s_ENUM */\n\n", interface->uppercase_name, e->uppercase_name); } @@ -1677,7 +1704,7 @@ emit_header(struct protocol *protocol, enum side side) wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) { - emit_enumerations(i); + emit_enumerations(i, side == SERVER); if (side == SERVER) { emit_structs(&i->request_list, i, side); @@ -1720,7 +1747,7 @@ emit_enum_header(struct protocol *protocol) protocol->uppercase_name); wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) { - emit_enumerations(i); + emit_enumerations(i, false); free_interface(i); } @@ -1849,7 +1876,8 @@ emit_code(struct protocol *protocol, enum visibility vis) if (protocol->copyright) format_text_to_comment(protocol->copyright, true); - printf("#include \n" + printf("#include \n" + "#include \n" "#include \n" "#include \"wayland-util.h\"\n\n"); diff --git a/tests/data/empty-code.c b/tests/data/empty-code.c index 6f0f6190..67382d20 100644 --- a/tests/data/empty-code.c +++ b/tests/data/empty-code.c @@ -1,5 +1,6 @@ /* SCANNER TEST */ +#include #include #include #include "wayland-util.h" diff --git a/tests/data/example-code.c b/tests/data/example-code.c index 2055c88e..37feed78 100644 --- a/tests/data/example-code.c +++ b/tests/data/example-code.c @@ -27,6 +27,7 @@ * SOFTWARE. */ +#include #include #include #include "wayland-util.h" diff --git a/tests/data/example-server.h b/tests/data/example-server.h index 7cfa4e7a..b0d9226d 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -901,6 +901,26 @@ enum wl_display_error { */ WL_DISPLAY_ERROR_NO_MEMORY = 2, }; +/** + * @ingroup iface_wl_display + * Validate a wl_display error value. + * + * @return true on success, false on error. + * @ref wl_display_error + */ +static inline bool +wl_display_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_DISPLAY_ERROR_INVALID_OBJECT: + return version >= 1; + case WL_DISPLAY_ERROR_INVALID_METHOD: + return version >= 1; + case WL_DISPLAY_ERROR_NO_MEMORY: + return version >= 1; + default: + return false; + } +} #endif /* WL_DISPLAY_ERROR_ENUM */ /** @@ -1174,6 +1194,26 @@ enum wl_shm_error { */ WL_SHM_ERROR_INVALID_FD = 2, }; +/** + * @ingroup iface_wl_shm + * Validate a wl_shm error value. + * + * @return true on success, false on error. + * @ref wl_shm_error + */ +static inline bool +wl_shm_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SHM_ERROR_INVALID_FORMAT: + return version >= 1; + case WL_SHM_ERROR_INVALID_STRIDE: + return version >= 1; + case WL_SHM_ERROR_INVALID_FD: + return version >= 1; + default: + return false; + } +} #endif /* WL_SHM_ERROR_ENUM */ #ifndef WL_SHM_FORMAT_ENUM @@ -1426,6 +1466,136 @@ enum wl_shm_format { */ WL_SHM_FORMAT_YVU444 = 0x34325659, }; +/** + * @ingroup iface_wl_shm + * Validate a wl_shm format value. + * + * @return true on success, false on error. + * @ref wl_shm_format + */ +static inline bool +wl_shm_format_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SHM_FORMAT_ARGB8888: + return version >= 1; + case WL_SHM_FORMAT_XRGB8888: + return version >= 1; + case WL_SHM_FORMAT_C8: + return version >= 1; + case WL_SHM_FORMAT_RGB332: + return version >= 1; + case WL_SHM_FORMAT_BGR233: + return version >= 1; + case WL_SHM_FORMAT_XRGB4444: + return version >= 1; + case WL_SHM_FORMAT_XBGR4444: + return version >= 1; + case WL_SHM_FORMAT_RGBX4444: + return version >= 1; + case WL_SHM_FORMAT_BGRX4444: + return version >= 1; + case WL_SHM_FORMAT_ARGB4444: + return version >= 1; + case WL_SHM_FORMAT_ABGR4444: + return version >= 1; + case WL_SHM_FORMAT_RGBA4444: + return version >= 1; + case WL_SHM_FORMAT_BGRA4444: + return version >= 1; + case WL_SHM_FORMAT_XRGB1555: + return version >= 1; + case WL_SHM_FORMAT_XBGR1555: + return version >= 1; + case WL_SHM_FORMAT_RGBX5551: + return version >= 1; + case WL_SHM_FORMAT_BGRX5551: + return version >= 1; + case WL_SHM_FORMAT_ARGB1555: + return version >= 1; + case WL_SHM_FORMAT_ABGR1555: + return version >= 1; + case WL_SHM_FORMAT_RGBA5551: + return version >= 1; + case WL_SHM_FORMAT_BGRA5551: + return version >= 1; + case WL_SHM_FORMAT_RGB565: + return version >= 1; + case WL_SHM_FORMAT_BGR565: + return version >= 1; + case WL_SHM_FORMAT_RGB888: + return version >= 1; + case WL_SHM_FORMAT_BGR888: + return version >= 1; + case WL_SHM_FORMAT_XBGR8888: + return version >= 1; + case WL_SHM_FORMAT_RGBX8888: + return version >= 1; + case WL_SHM_FORMAT_BGRX8888: + return version >= 1; + case WL_SHM_FORMAT_ABGR8888: + return version >= 1; + case WL_SHM_FORMAT_RGBA8888: + return version >= 1; + case WL_SHM_FORMAT_BGRA8888: + return version >= 1; + case WL_SHM_FORMAT_XRGB2101010: + return version >= 1; + case WL_SHM_FORMAT_XBGR2101010: + return version >= 1; + case WL_SHM_FORMAT_RGBX1010102: + return version >= 1; + case WL_SHM_FORMAT_BGRX1010102: + return version >= 1; + case WL_SHM_FORMAT_ARGB2101010: + return version >= 1; + case WL_SHM_FORMAT_ABGR2101010: + return version >= 1; + case WL_SHM_FORMAT_RGBA1010102: + return version >= 1; + case WL_SHM_FORMAT_BGRA1010102: + return version >= 1; + case WL_SHM_FORMAT_YUYV: + return version >= 1; + case WL_SHM_FORMAT_YVYU: + return version >= 1; + case WL_SHM_FORMAT_UYVY: + return version >= 1; + case WL_SHM_FORMAT_VYUY: + return version >= 1; + case WL_SHM_FORMAT_AYUV: + return version >= 1; + case WL_SHM_FORMAT_NV12: + return version >= 1; + case WL_SHM_FORMAT_NV21: + return version >= 1; + case WL_SHM_FORMAT_NV16: + return version >= 1; + case WL_SHM_FORMAT_NV61: + return version >= 1; + case WL_SHM_FORMAT_YUV410: + return version >= 1; + case WL_SHM_FORMAT_YVU410: + return version >= 1; + case WL_SHM_FORMAT_YUV411: + return version >= 1; + case WL_SHM_FORMAT_YVU411: + return version >= 1; + case WL_SHM_FORMAT_YUV420: + return version >= 1; + case WL_SHM_FORMAT_YVU420: + return version >= 1; + case WL_SHM_FORMAT_YUV422: + return version >= 1; + case WL_SHM_FORMAT_YVU422: + return version >= 1; + case WL_SHM_FORMAT_YUV444: + return version >= 1; + case WL_SHM_FORMAT_YVU444: + return version >= 1; + default: + return false; + } +} #endif /* WL_SHM_FORMAT_ENUM */ /** @@ -1536,6 +1706,28 @@ enum wl_data_offer_error { */ WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, }; +/** + * @ingroup iface_wl_data_offer + * Validate a wl_data_offer error value. + * + * @return true on success, false on error. + * @ref wl_data_offer_error + */ +static inline bool +wl_data_offer_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_DATA_OFFER_ERROR_INVALID_FINISH: + return version >= 1; + case WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK: + return version >= 1; + case WL_DATA_OFFER_ERROR_INVALID_ACTION: + return version >= 1; + case WL_DATA_OFFER_ERROR_INVALID_OFFER: + return version >= 1; + default: + return false; + } +} #endif /* WL_DATA_OFFER_ERROR_ENUM */ /** @@ -1748,6 +1940,24 @@ enum wl_data_source_error { */ WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, }; +/** + * @ingroup iface_wl_data_source + * Validate a wl_data_source error value. + * + * @return true on success, false on error. + * @ref wl_data_source_error + */ +static inline bool +wl_data_source_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK: + return version >= 1; + case WL_DATA_SOURCE_ERROR_INVALID_SOURCE: + return version >= 1; + default: + return false; + } +} #endif /* WL_DATA_SOURCE_ERROR_ENUM */ /** @@ -1920,6 +2130,22 @@ enum wl_data_device_error { */ WL_DATA_DEVICE_ERROR_ROLE = 0, }; +/** + * @ingroup iface_wl_data_device + * Validate a wl_data_device error value. + * + * @return true on success, false on error. + * @ref wl_data_device_error + */ +static inline bool +wl_data_device_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_DATA_DEVICE_ERROR_ROLE: + return version >= 1; + default: + return false; + } +} #endif /* WL_DATA_DEVICE_ERROR_ENUM */ /** @@ -2161,6 +2387,28 @@ enum wl_data_device_manager_dnd_action { */ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, }; +/** + * @ingroup iface_wl_data_device_manager + * Validate a wl_data_device_manager dnd_action value. + * + * @return true on success, false on error. + * @ref wl_data_device_manager_dnd_action + */ +static inline bool +wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: + return version >= 1; + case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: + return version >= 1; + case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: + return version >= 1; + case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK: + return version >= 1; + default: + return false; + } +} #endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ /** @@ -2208,6 +2456,22 @@ enum wl_shell_error { */ WL_SHELL_ERROR_ROLE = 0, }; +/** + * @ingroup iface_wl_shell + * Validate a wl_shell error value. + * + * @return true on success, false on error. + * @ref wl_shell_error + */ +static inline bool +wl_shell_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SHELL_ERROR_ROLE: + return version >= 1; + default: + return false; + } +} #endif /* WL_SHELL_ERROR_ENUM */ /** @@ -2287,6 +2551,38 @@ enum wl_shell_surface_resize { */ WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, }; +/** + * @ingroup iface_wl_shell_surface + * Validate a wl_shell_surface resize value. + * + * @return true on success, false on error. + * @ref wl_shell_surface_resize + */ +static inline bool +wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SHELL_SURFACE_RESIZE_NONE: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_TOP: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_BOTTOM: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_LEFT: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_RIGHT: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: + return version >= 1; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} #endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ #ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM @@ -2304,6 +2600,22 @@ enum wl_shell_surface_transient { */ WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, }; +/** + * @ingroup iface_wl_shell_surface + * Validate a wl_shell_surface transient value. + * + * @return true on success, false on error. + * @ref wl_shell_surface_transient + */ +static inline bool +wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SHELL_SURFACE_TRANSIENT_INACTIVE: + return version >= 1; + default: + return false; + } +} #endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ #ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM @@ -2334,6 +2646,28 @@ enum wl_shell_surface_fullscreen_method { */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, }; +/** + * @ingroup iface_wl_shell_surface + * Validate a wl_shell_surface fullscreen_method value. + * + * @return true on success, false on error. + * @ref wl_shell_surface_fullscreen_method + */ +static inline bool +wl_shell_surface_fullscreen_method_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: + return version >= 1; + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: + return version >= 1; + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: + return version >= 1; + case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: + return version >= 1; + default: + return false; + } +} #endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ /** @@ -2666,6 +3000,24 @@ enum wl_surface_error { */ WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, }; +/** + * @ingroup iface_wl_surface + * Validate a wl_surface error value. + * + * @return true on success, false on error. + * @ref wl_surface_error + */ +static inline bool +wl_surface_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SURFACE_ERROR_INVALID_SCALE: + return version >= 1; + case WL_SURFACE_ERROR_INVALID_TRANSFORM: + return version >= 1; + default: + return false; + } +} #endif /* WL_SURFACE_ERROR_ENUM */ /** @@ -3125,6 +3477,26 @@ enum wl_seat_capability { */ WL_SEAT_CAPABILITY_TOUCH = 4, }; +/** + * @ingroup iface_wl_seat + * Validate a wl_seat capability value. + * + * @return true on success, false on error. + * @ref wl_seat_capability + */ +static inline bool +wl_seat_capability_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SEAT_CAPABILITY_POINTER: + return version >= 1; + case WL_SEAT_CAPABILITY_KEYBOARD: + return version >= 1; + case WL_SEAT_CAPABILITY_TOUCH: + return version >= 1; + default: + return false; + } +} #endif /* WL_SEAT_CAPABILITY_ENUM */ /** @@ -3249,6 +3621,22 @@ enum wl_pointer_error { */ WL_POINTER_ERROR_ROLE = 0, }; +/** + * @ingroup iface_wl_pointer + * Validate a wl_pointer error value. + * + * @return true on success, false on error. + * @ref wl_pointer_error + */ +static inline bool +wl_pointer_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_POINTER_ERROR_ROLE: + return version >= 1; + default: + return false; + } +} #endif /* WL_POINTER_ERROR_ENUM */ #ifndef WL_POINTER_BUTTON_STATE_ENUM @@ -3270,6 +3658,24 @@ enum wl_pointer_button_state { */ WL_POINTER_BUTTON_STATE_PRESSED = 1, }; +/** + * @ingroup iface_wl_pointer + * Validate a wl_pointer button_state value. + * + * @return true on success, false on error. + * @ref wl_pointer_button_state + */ +static inline bool +wl_pointer_button_state_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_POINTER_BUTTON_STATE_RELEASED: + return version >= 1; + case WL_POINTER_BUTTON_STATE_PRESSED: + return version >= 1; + default: + return false; + } +} #endif /* WL_POINTER_BUTTON_STATE_ENUM */ #ifndef WL_POINTER_AXIS_ENUM @@ -3290,6 +3696,24 @@ enum wl_pointer_axis { */ WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, }; +/** + * @ingroup iface_wl_pointer + * Validate a wl_pointer axis value. + * + * @return true on success, false on error. + * @ref wl_pointer_axis + */ +static inline bool +wl_pointer_axis_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + return version >= 1; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + return version >= 1; + default: + return false; + } +} #endif /* WL_POINTER_AXIS_ENUM */ #ifndef WL_POINTER_AXIS_SOURCE_ENUM @@ -3338,6 +3762,28 @@ enum wl_pointer_axis_source { * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 +/** + * @ingroup iface_wl_pointer + * Validate a wl_pointer axis_source value. + * + * @return true on success, false on error. + * @ref wl_pointer_axis_source + */ +static inline bool +wl_pointer_axis_source_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_POINTER_AXIS_SOURCE_WHEEL: + return version >= 1; + case WL_POINTER_AXIS_SOURCE_FINGER: + return version >= 1; + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: + return version >= 1; + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: + return version >= 6; + default: + return false; + } +} #endif /* WL_POINTER_AXIS_SOURCE_ENUM */ /** @@ -3599,6 +4045,24 @@ enum wl_keyboard_keymap_format { */ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, }; +/** + * @ingroup iface_wl_keyboard + * Validate a wl_keyboard keymap_format value. + * + * @return true on success, false on error. + * @ref wl_keyboard_keymap_format + */ +static inline bool +wl_keyboard_keymap_format_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: + return version >= 1; + case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: + return version >= 1; + default: + return false; + } +} #endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ #ifndef WL_KEYBOARD_KEY_STATE_ENUM @@ -3619,6 +4083,24 @@ enum wl_keyboard_key_state { */ WL_KEYBOARD_KEY_STATE_PRESSED = 1, }; +/** + * @ingroup iface_wl_keyboard + * Validate a wl_keyboard key_state value. + * + * @return true on success, false on error. + * @ref wl_keyboard_key_state + */ +static inline bool +wl_keyboard_key_state_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_KEYBOARD_KEY_STATE_RELEASED: + return version >= 1; + case WL_KEYBOARD_KEY_STATE_PRESSED: + return version >= 1; + default: + return false; + } +} #endif /* WL_KEYBOARD_KEY_STATE_ENUM */ /** @@ -3945,6 +4427,32 @@ enum wl_output_subpixel { */ WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, }; +/** + * @ingroup iface_wl_output + * Validate a wl_output subpixel value. + * + * @return true on success, false on error. + * @ref wl_output_subpixel + */ +static inline bool +wl_output_subpixel_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_OUTPUT_SUBPIXEL_UNKNOWN: + return version >= 1; + case WL_OUTPUT_SUBPIXEL_NONE: + return version >= 1; + case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: + return version >= 1; + case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: + return version >= 1; + case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: + return version >= 1; + case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: + return version >= 1; + default: + return false; + } +} #endif /* WL_OUTPUT_SUBPIXEL_ENUM */ #ifndef WL_OUTPUT_TRANSFORM_ENUM @@ -3999,6 +4507,36 @@ enum wl_output_transform { */ WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, }; +/** + * @ingroup iface_wl_output + * Validate a wl_output transform value. + * + * @return true on success, false on error. + * @ref wl_output_transform + */ +static inline bool +wl_output_transform_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_OUTPUT_TRANSFORM_NORMAL: + return version >= 1; + case WL_OUTPUT_TRANSFORM_90: + return version >= 1; + case WL_OUTPUT_TRANSFORM_180: + return version >= 1; + case WL_OUTPUT_TRANSFORM_270: + return version >= 1; + case WL_OUTPUT_TRANSFORM_FLIPPED: + return version >= 1; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + return version >= 1; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + return version >= 1; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + return version >= 1; + default: + return false; + } +} #endif /* WL_OUTPUT_TRANSFORM_ENUM */ #ifndef WL_OUTPUT_MODE_ENUM @@ -4020,6 +4558,24 @@ enum wl_output_mode { */ WL_OUTPUT_MODE_PREFERRED = 0x2, }; +/** + * @ingroup iface_wl_output + * Validate a wl_output mode value. + * + * @return true on success, false on error. + * @ref wl_output_mode + */ +static inline bool +wl_output_mode_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_OUTPUT_MODE_CURRENT: + return version >= 1; + case WL_OUTPUT_MODE_PREFERRED: + return version >= 1; + default: + return false; + } +} #endif /* WL_OUTPUT_MODE_ENUM */ /** @@ -4188,6 +4744,22 @@ enum wl_subcompositor_error { */ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, }; +/** + * @ingroup iface_wl_subcompositor + * Validate a wl_subcompositor error value. + * + * @return true on success, false on error. + * @ref wl_subcompositor_error + */ +static inline bool +wl_subcompositor_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE: + return version >= 1; + default: + return false; + } +} #endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ /** @@ -4243,6 +4815,22 @@ enum wl_subsurface_error { */ WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, }; +/** + * @ingroup iface_wl_subsurface + * Validate a wl_subsurface error value. + * + * @return true on success, false on error. + * @ref wl_subsurface_error + */ +static inline bool +wl_subsurface_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WL_SUBSURFACE_ERROR_BAD_SURFACE: + return version >= 1; + default: + return false; + } +} #endif /* WL_SUBSURFACE_ERROR_ENUM */ /** diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h index 348d2dc2..e5e21931 100644 --- a/tests/data/small-client-core.h +++ b/tests/data/small-client-core.h @@ -80,11 +80,20 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_THIRD = 2, + /** + * this is a negative value + * @since 2 + */ + INTF_A_FOO_NEGATIVE = -1, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ /** diff --git a/tests/data/small-client.h b/tests/data/small-client.h index 8c6abc50..c81b70f5 100644 --- a/tests/data/small-client.h +++ b/tests/data/small-client.h @@ -80,11 +80,20 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_THIRD = 2, + /** + * this is a negative value + * @since 2 + */ + INTF_A_FOO_NEGATIVE = -1, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ /** diff --git a/tests/data/small-code-core.c b/tests/data/small-code-core.c index bd6d33de..88e82579 100644 --- a/tests/data/small-code-core.c +++ b/tests/data/small-code-core.c @@ -25,6 +25,7 @@ * SOFTWARE. */ +#include #include #include #include "wayland-util.h" diff --git a/tests/data/small-code.c b/tests/data/small-code.c index bd6d33de..88e82579 100644 --- a/tests/data/small-code.c +++ b/tests/data/small-code.c @@ -25,6 +25,7 @@ * SOFTWARE. */ +#include #include #include #include "wayland-util.h" diff --git a/tests/data/small-private-code.c b/tests/data/small-private-code.c index fe035ffe..16794319 100644 --- a/tests/data/small-private-code.c +++ b/tests/data/small-private-code.c @@ -25,6 +25,7 @@ * SOFTWARE. */ +#include #include #include #include "wayland-util.h" diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h index f0fd1f90..ff19d670 100644 --- a/tests/data/small-server-core.h +++ b/tests/data/small-server-core.h @@ -83,11 +83,42 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_THIRD = 2, + /** + * this is a negative value + * @since 2 + */ + INTF_A_FOO_NEGATIVE = -1, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + * Validate a intf_A foo value. + * + * @return true on success, false on error. + * @ref intf_A_foo + */ +static inline bool +intf_A_foo_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case INTF_A_FOO_FIRST: + return version >= 1; + case INTF_A_FOO_SECOND: + return version >= 1; + case INTF_A_FOO_THIRD: + return version >= 2; + case (uint32_t)INTF_A_FOO_NEGATIVE: + return version >= 2; + default: + return false; + } +} #endif /* INTF_A_FOO_ENUM */ /** diff --git a/tests/data/small-server.h b/tests/data/small-server.h index 22b81133..13fd1edc 100644 --- a/tests/data/small-server.h +++ b/tests/data/small-server.h @@ -83,11 +83,42 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_THIRD = 2, + /** + * this is a negative value + * @since 2 + */ + INTF_A_FOO_NEGATIVE = -1, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + * Validate a intf_A foo value. + * + * @return true on success, false on error. + * @ref intf_A_foo + */ +static inline bool +intf_A_foo_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case INTF_A_FOO_FIRST: + return version >= 1; + case INTF_A_FOO_SECOND: + return version >= 1; + case INTF_A_FOO_THIRD: + return version >= 2; + case (uint32_t)INTF_A_FOO_NEGATIVE: + return version >= 2; + default: + return false; + } +} #endif /* INTF_A_FOO_ENUM */ /** diff --git a/tests/data/small.xml b/tests/data/small.xml index 832ed0e1..685c8915 100644 --- a/tests/data/small.xml +++ b/tests/data/small.xml @@ -53,6 +53,7 @@ + diff --git a/tests/enum-validator-test.c b/tests/enum-validator-test.c new file mode 100644 index 00000000..92037cff --- /dev/null +++ b/tests/enum-validator-test.c @@ -0,0 +1,13 @@ +#include +#include "data/small-server-core.h" + +int +main(int argc, char *argv[]) { + assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 1)); + assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 2)); + + assert(!intf_A_foo_is_valid(INTF_A_FOO_THIRD, 1)); + assert(intf_A_foo_is_valid(INTF_A_FOO_THIRD, 2)); + + assert(intf_A_foo_is_valid(INTF_A_FOO_NEGATIVE, 2)); +} diff --git a/tests/meson.build b/tests/meson.build index 236f08c0..2c22b82a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -158,6 +158,7 @@ tests = { wayland_client_protocol_h, wayland_server_protocol_h, ], + 'enum-validator-test': [], } foreach test_name, test_extra_sources: tests From 16aee2ec3829b37f4db623ab9ddab1b789bdd2e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9=20Vulquin?= Date: Thu, 28 Mar 2024 13:44:36 +0100 Subject: [PATCH 0995/1152] xcursor: catch theme inheritance loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of currently, when an xcursor theme depends on itself or another theme that will eventually depend on it, `xcursor_load_theme` will recurse infinitely while processing the inherits. This change introduces a stack-allocated linked list of visited nodes by name, and skips any already visited nodes in the inherit list. Side effects: * Since the linked list is stack-allocated, there is a potential for an overflow if there is a very long list of dependencies. If this turns out to be a legitimate concern, the linked list is trivial to convert to being heap-allocated. * There is an existing linked list (technically doubly linked list) implementation in the wayland codebase. As of currently, the xcursor codebase does not refer to it. Consequently, this change writes a minimal single linked list implementation to utilize directly. This changeset fixes #317. Signed-off-by: Chloé Vulquin --- cursor/xcursor.c | 112 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 35 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 6766c564..0d5761f2 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -726,6 +726,78 @@ load_all_cursors_from_dir(const char *path, int size, closedir(dir); } +struct xcursor_nodelist { + size_t nodelen; + const char *node; + struct xcursor_nodelist *next; +}; + +static bool +nodelist_contains(struct xcursor_nodelist *nodelist, const char *s, size_t ss) +{ + struct xcursor_nodelist *vi; + + for (vi = nodelist; vi && vi->node; vi = vi->next) { + if (vi->nodelen == ss && !strncmp(s, vi->node, vi->nodelen)) + return true; + } + return false; +} + +static void +xcursor_load_theme_protected(const char *theme, int size, + void (*load_callback)(struct xcursor_images *, void *), + void *user_data, + struct xcursor_nodelist *visited_nodes) +{ + char *full, *dir; + char *inherits = NULL; + const char *path, *i; + char *xcursor_path; + size_t si; + struct xcursor_nodelist current_node; + + if (!theme) + theme = "default"; + + current_node.next = visited_nodes; + current_node.node = theme; + current_node.nodelen = strlen(theme); + visited_nodes = ¤t_node; + + xcursor_path = xcursor_library_path(); + for (path = xcursor_path; + path; + path = xcursor_next_path(path)) { + dir = xcursor_build_theme_dir(path, theme); + if (!dir) + continue; + + full = xcursor_build_fullname(dir, "cursors", ""); + load_all_cursors_from_dir(full, size, load_callback, + user_data); + free(full); + + if (!inherits) { + full = xcursor_build_fullname(dir, "", "index.theme"); + inherits = xcursor_theme_inherits(full); + free(full); + } + + free(dir); + } + + for (i = inherits; i; i = xcursor_next_path(i)) { + si = strlen(i); + if (nodelist_contains(visited_nodes, i, si)) + continue; + xcursor_load_theme_protected(i, size, load_callback, user_data, visited_nodes); + } + + free(inherits); + free(xcursor_path); +} + /** Load all the cursor of a theme * * This function loads all the cursor images of a given theme and its @@ -750,39 +822,9 @@ xcursor_load_theme(const char *theme, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data) { - char *full, *dir; - char *inherits = NULL; - const char *path, *i; - char *xcursor_path; - - if (!theme) - theme = "default"; - - xcursor_path = xcursor_library_path(); - for (path = xcursor_path; - path; - path = xcursor_next_path(path)) { - dir = xcursor_build_theme_dir(path, theme); - if (!dir) - continue; - - full = xcursor_build_fullname(dir, "cursors", ""); - load_all_cursors_from_dir(full, size, load_callback, - user_data); - free(full); - - if (!inherits) { - full = xcursor_build_fullname(dir, "", "index.theme"); - inherits = xcursor_theme_inherits(full); - free(full); - } - - free(dir); - } - - for (i = inherits; i; i = xcursor_next_path(i)) - xcursor_load_theme(i, size, load_callback, user_data); - - free(inherits); - free(xcursor_path); + xcursor_load_theme_protected(theme, + size, + load_callback, + user_data, + NULL); } From ee12e69b8fb8c55460126e4e527eb4f7fee5526e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 19 Jul 2023 12:50:34 +0200 Subject: [PATCH 0996/1152] Add support for the deprecated-since XML attribute This marks a request, event or enum entry as deprecated since a given version. Note that it's not clear what it means if an entry is deprecated at some version, and the enum is used from some completely different interface than where it was defined. However, that's a more general issue with enums, see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/435 Signed-off-by: Simon Ser References: https://gitlab.freedesktop.org/wayland/wayland/-/issues/89 --- protocol/wayland.dtd | 3 +++ src/scanner.c | 54 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd index ee062eea..b97372c5 100644 --- a/protocol/wayland.dtd +++ b/protocol/wayland.dtd @@ -8,10 +8,12 @@ + + @@ -21,6 +23,7 @@ + diff --git a/src/scanner.c b/src/scanner.c index 3f528f31..95524513 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -175,7 +175,7 @@ struct interface { char *name; char *uppercase_name; int version; - int since; + int since, deprecated_since; struct wl_list request_list; struct wl_list event_list; struct wl_list enumeration_list; @@ -194,7 +194,7 @@ struct message { int type_index; int all_null; int destructor; - int since; + int since, deprecated_since; struct description *description; }; @@ -234,7 +234,7 @@ struct entry { char *uppercase_name; char *value; char *summary; - int since; + int since, deprecated_since; struct wl_list link; struct description *description; }; @@ -697,6 +697,25 @@ version_from_since(struct parse_context *ctx, const char *since) return version; } +static int +version_from_deprecated_since(struct parse_context *ctx, const char *deprecated_since) +{ + int version; + + if (deprecated_since == NULL) + return 0; + + version = strtouint(deprecated_since); + if (version == -1) { + fail(&ctx->loc, "invalid integer (%s)\n", deprecated_since); + } else if (version > ctx->interface->version) { + fail(&ctx->loc, "deprecated-since (%u) larger than version (%u)\n", + version, ctx->interface->version); + } + + return version; +} + static void start_element(void *data, const char *element_name, const char **atts) { @@ -713,6 +732,7 @@ start_element(void *data, const char *element_name, const char **atts) const char *value = NULL; const char *summary = NULL; const char *since = NULL; + const char *deprecated_since = NULL; const char *allow_null = NULL; const char *enumeration_name = NULL; const char *bitfield = NULL; @@ -737,6 +757,8 @@ start_element(void *data, const char *element_name, const char **atts) summary = atts[i + 1]; if (strcmp(atts[i], "since") == 0) since = atts[i + 1]; + if (strcmp(atts[i], "deprecated-since") == 0) + deprecated_since = atts[i + 1]; if (strcmp(atts[i], "allow-null") == 0) allow_null = atts[i + 1]; if (strcmp(atts[i], "enum") == 0) @@ -786,12 +808,18 @@ start_element(void *data, const char *element_name, const char **atts) message->destructor = 1; version = version_from_since(ctx, since); - if (version < ctx->interface->since) warn(&ctx->loc, "since version not increasing\n"); ctx->interface->since = version; message->since = version; + version = version_from_deprecated_since(ctx, deprecated_since); + if (version > 0 && version <= message->since) + fail(&ctx->loc, "deprecated-since version (%d) smaller " + "or equal to since version (%u)\n", + version, message->since); + message->deprecated_since = version; + if (strcmp(name, "destroy") == 0 && !message->destructor) fail(&ctx->loc, "destroy request should be destructor type"); @@ -872,13 +900,20 @@ start_element(void *data, const char *element_name, const char **atts) validate_identifier(&ctx->loc, name, TRAILING_IDENT); entry = create_entry(name, value); - version = version_from_since(ctx, since); + version = version_from_since(ctx, since); if (version < ctx->enumeration->since) warn(&ctx->loc, "since version not increasing\n"); ctx->enumeration->since = version; entry->since = version; + version = version_from_deprecated_since(ctx, deprecated_since); + if (version > 0 && version <= entry->since) + fail(&ctx->loc, "deprecated-since version (%d) smaller " + "or equal to since version (%u)\n", + version, entry->since); + entry->deprecated_since = version; + if (summary) entry->summary = xstrdup(summary); else @@ -1380,6 +1415,9 @@ emit_enumerations(struct interface *interface, bool with_validators) } if (entry->since > 1) printf("\t * @since %d\n", entry->since); + if (entry->deprecated_since > 0) + printf("\t * @deprecated Deprecated since version %d\n", + entry->deprecated_since); printf("\t */\n"); } printf("\t%s_%s_%s = %s,\n", @@ -1471,9 +1509,11 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid printf("\t * @param %s %s\n", a->name, a->summary); } - if (m->since > 1) { + if (m->since > 1) printf("\t * @since %d\n", m->since); - } + if (m->deprecated_since > 0) + printf("\t * @deprecated Deprecated since version %d\n", + m->deprecated_since); printf("\t */\n"); printf("\tvoid (*%s)(", m->name); From da8e1bbc45bde2debc6c8a1f9e3c67cb964de968 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 12 Mar 2024 14:21:54 +0100 Subject: [PATCH 0997/1152] protocol: mark wl_pointer.axis_discrete as deprecated Since version 8, this event isn't sent anymore. Signed-off-by: Simon Ser --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 4c376160..b3873304 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2296,7 +2296,7 @@ - + Discrete step information for scroll and other axes. From 80c65f862f7919691d3b0d31810f5a40f8675f37 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 8 Apr 2024 13:32:31 +0200 Subject: [PATCH 0998/1152] tests: add deprecated-since attributes Add a new event and enum entry to small.xml with a deprecated-since attribute to exercise the scanner code generation. Signed-off-by: Simon Ser --- tests/data/small-client-core.h | 20 ++++++++++++++++++++ tests/data/small-client.h | 20 ++++++++++++++++++++ tests/data/small-code-core.c | 3 ++- tests/data/small-code.c | 3 ++- tests/data/small-private-code.c | 3 ++- tests/data/small-server-core.h | 28 ++++++++++++++++++++++++++++ tests/data/small-server.h | 28 ++++++++++++++++++++++++++++ tests/data/small.xml | 3 +++ 8 files changed, 105 insertions(+), 3 deletions(-) diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h index e5e21931..0e722441 100644 --- a/tests/data/small-client-core.h +++ b/tests/data/small-client-core.h @@ -85,6 +85,12 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_NEGATIVE = -1, + /** + * this is a deprecated value + * @since 2 + * @deprecated Deprecated since version 3 + */ + INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A @@ -94,6 +100,10 @@ enum intf_A_foo { * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ /** @@ -105,6 +115,12 @@ struct intf_A_listener { */ void (*hey)(void *data, struct intf_A *intf_A); + /** + * @since 2 + * @deprecated Deprecated since version 3 + */ + void (*yo)(void *data, + struct intf_A *intf_A); }; /** @@ -126,6 +142,10 @@ intf_A_add_listener(struct intf_A *intf_A, * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A diff --git a/tests/data/small-client.h b/tests/data/small-client.h index c81b70f5..ad435923 100644 --- a/tests/data/small-client.h +++ b/tests/data/small-client.h @@ -85,6 +85,12 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_NEGATIVE = -1, + /** + * this is a deprecated value + * @since 2 + * @deprecated Deprecated since version 3 + */ + INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A @@ -94,6 +100,10 @@ enum intf_A_foo { * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ /** @@ -105,6 +115,12 @@ struct intf_A_listener { */ void (*hey)(void *data, struct intf_A *intf_A); + /** + * @since 2 + * @deprecated Deprecated since version 3 + */ + void (*yo)(void *data, + struct intf_A *intf_A); }; /** @@ -126,6 +142,10 @@ intf_A_add_listener(struct intf_A *intf_A, * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A diff --git a/tests/data/small-code-core.c b/tests/data/small-code-core.c index 88e82579..b6545493 100644 --- a/tests/data/small-code-core.c +++ b/tests/data/small-code-core.c @@ -52,11 +52,12 @@ static const struct wl_message intf_A_requests[] = { static const struct wl_message intf_A_events[] = { { "hey", "", small_test_types + 0 }, + { "yo", "2", small_test_types + 0 }, }; WL_EXPORT const struct wl_interface intf_A_interface = { "intf_A", 3, 3, intf_A_requests, - 1, intf_A_events, + 2, intf_A_events, }; diff --git a/tests/data/small-code.c b/tests/data/small-code.c index 88e82579..b6545493 100644 --- a/tests/data/small-code.c +++ b/tests/data/small-code.c @@ -52,11 +52,12 @@ static const struct wl_message intf_A_requests[] = { static const struct wl_message intf_A_events[] = { { "hey", "", small_test_types + 0 }, + { "yo", "2", small_test_types + 0 }, }; WL_EXPORT const struct wl_interface intf_A_interface = { "intf_A", 3, 3, intf_A_requests, - 1, intf_A_events, + 2, intf_A_events, }; diff --git a/tests/data/small-private-code.c b/tests/data/small-private-code.c index 16794319..b2bbf0a3 100644 --- a/tests/data/small-private-code.c +++ b/tests/data/small-private-code.c @@ -62,11 +62,12 @@ static const struct wl_message intf_A_requests[] = { static const struct wl_message intf_A_events[] = { { "hey", "", small_test_types + 0 }, + { "yo", "2", small_test_types + 0 }, }; WL_PRIVATE const struct wl_interface intf_A_interface = { "intf_A", 3, 3, intf_A_requests, - 1, intf_A_events, + 2, intf_A_events, }; diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h index ff19d670..e696cde7 100644 --- a/tests/data/small-server-core.h +++ b/tests/data/small-server-core.h @@ -88,6 +88,12 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_NEGATIVE = -1, + /** + * this is a deprecated value + * @since 2 + * @deprecated Deprecated since version 3 + */ + INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A @@ -97,6 +103,10 @@ enum intf_A_foo { * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 /** * @ingroup iface_intf_A * Validate a intf_A foo value. @@ -115,6 +125,8 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) { return version >= 2; case (uint32_t)INTF_A_FOO_NEGATIVE: return version >= 2; + case INTF_A_FOO_DEPRECATED: + return version >= 2; default: return false; } @@ -151,11 +163,16 @@ struct intf_A_interface { }; #define INTF_A_HEY 0 +#define INTF_A_YO 1 /** * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A @@ -181,6 +198,17 @@ intf_A_send_hey(struct wl_resource *resource_) wl_resource_post_event(resource_, INTF_A_HEY); } +/** + * @ingroup iface_intf_A + * Sends an yo event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +intf_A_send_yo(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, INTF_A_YO); +} + #ifdef __cplusplus } #endif diff --git a/tests/data/small-server.h b/tests/data/small-server.h index 13fd1edc..009d9cdd 100644 --- a/tests/data/small-server.h +++ b/tests/data/small-server.h @@ -88,6 +88,12 @@ enum intf_A_foo { * @since 2 */ INTF_A_FOO_NEGATIVE = -1, + /** + * this is a deprecated value + * @since 2 + * @deprecated Deprecated since version 3 + */ + INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A @@ -97,6 +103,10 @@ enum intf_A_foo { * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 /** * @ingroup iface_intf_A * Validate a intf_A foo value. @@ -115,6 +125,8 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) { return version >= 2; case (uint32_t)INTF_A_FOO_NEGATIVE: return version >= 2; + case INTF_A_FOO_DEPRECATED: + return version >= 2; default: return false; } @@ -151,11 +163,16 @@ struct intf_A_interface { }; #define INTF_A_HEY 0 +#define INTF_A_YO 1 /** * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 +/** + * @ingroup iface_intf_A + */ +#define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A @@ -181,6 +198,17 @@ intf_A_send_hey(struct wl_resource *resource_) wl_resource_post_event(resource_, INTF_A_HEY); } +/** + * @ingroup iface_intf_A + * Sends an yo event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +intf_A_send_yo(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, INTF_A_YO); +} + #ifdef __cplusplus } #endif diff --git a/tests/data/small.xml b/tests/data/small.xml index 685c8915..ac527795 100644 --- a/tests/data/small.xml +++ b/tests/data/small.xml @@ -49,11 +49,14 @@ + + + From 6e1db539168562020203498d97f8222cd06a4a43 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 17 Apr 2024 13:39:27 +0200 Subject: [PATCH 0999/1152] client: fix invalid doc command for WL_MARSHAL_FLAG_DESTROY Fixes the following warning: src/wayland-client-core.h:125: warning: Found non-existing group 'wl_proxy' for the command '@ingroup', ignoring command "\memberof" cannot be used here because it only works on functions. The docs for "\memberof" say that "\relates" works in a similar way. While at it, use a "\" command instead of a "@" command for consistency with the rest of the file. Signed-off-by: Simon Ser --- src/wayland-client-core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index a9d620e3..a4ca4e5d 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -120,7 +120,7 @@ struct wl_display; struct wl_event_queue; /** Destroy proxy after marshalling - * @ingroup wl_proxy + * \relates wl_proxy */ #define WL_MARSHAL_FLAG_DESTROY (1 << 0) From 9069af78a71f6b2aadb11334e5bef9a670a5043d Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 3 Apr 2024 16:20:47 +0200 Subject: [PATCH 1000/1152] protocol: define content updates and their internal queue Multiple protocols use the term content update without a fill definition. It makes sense to define it in the core protocol so that not every other protocol has to define it. This is supposed to retain the current semantics and only changes the documentation while defining new terms. Signed-off-by: Sebastian Wick --- protocol/wayland.xml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index b3873304..091fa15b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1656,16 +1656,18 @@ Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, - as opposed to the current state in use by the compositor. A commit - request atomically applies all pending state, replacing the current - state. After commit, the new pending state is as documented for each - related request. + as opposed to the active state in use by the compositor. - On commit, a pending wl_buffer is applied first, and all other state - second. This means that all coordinates in double-buffered state are - relative to the new wl_buffer coming into use, except for - wl_surface.attach itself. If there is no pending wl_buffer, the - coordinates are relative to the current surface contents. + A commit request atomically creates a content update from the pending + state, even if the pending state has not been touched. The content + update is placed in a queue until it becomes active. After commit, the + new pending state is as documented for each related request. + + When the content update is applied, the wl_buffer is applied before all + other state. This means that all coordinates in double-buffered state + are relative to the newly attached wl_buffers, except for + wl_surface.attach itself. If there is no newly attached wl_buffer, the + coordinates are relative to the previous content update. All requests that need a commit to become effective are documented to affect double-buffered state. From e60c631ff2860de1d9f064f4f438c0412a6dea6b Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Sat, 20 Apr 2024 11:21:04 -0500 Subject: [PATCH 1001/1152] client: print debug events that have no listener Currently WAYLAND_DEBUG text ignores events that have no listener. It can be helpful to know when you're receiving unhandled events, as you may have forgotten to add a listener, or adding a dispatch may have magically seemed to fix code that doesn't appear to be dispatching anything. Signed-off-by: Derek Foreman --- src/wayland-client.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index 75fad4ff..9cf27939 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1647,10 +1647,16 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) validate_closure_objects(closure); proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); + + if (debug_client) { + bool discarded = proxy_destroyed || + !(proxy->dispatcher || proxy->object.implementation); + + wl_closure_print(closure, &proxy->object, false, discarded, + id_from_object, queue->name); + } + if (proxy_destroyed) { - if (debug_client) - wl_closure_print(closure, &proxy->object, false, true, - id_from_object, queue->name); destroy_queued_closure(closure); return; } @@ -1658,17 +1664,9 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) pthread_mutex_unlock(&display->mutex); if (proxy->dispatcher) { - if (debug_client) - wl_closure_print(closure, &proxy->object, false, false, - id_from_object, queue->name); - wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { - if (debug_client) - wl_closure_print(closure, &proxy->object, false, false, - id_from_object, queue->name); - wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); } From 69633202180acce9d0d5ab4037d80291c71b2307 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 25 Apr 2024 17:46:07 +0200 Subject: [PATCH 1002/1152] build: bump to version 1.22.91 for the alpha release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index f6f7dd84..5661e7ac 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.22.90', + version: '1.22.91', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From 9e4f25692792df679660b390324842c19c0031a5 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 17 Apr 2024 11:24:50 +0200 Subject: [PATCH 1003/1152] protocol: explicitly describe wl_keyboard state And the allowed state transitions. There has been some confusion regarding which state transitions are allowed. This change should clarify this. Signed-off-by: Julian Orth --- protocol/wayland.xml | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 091fa15b..97ad2eb2 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2424,6 +2424,16 @@ The wl_keyboard interface represents one or more keyboards associated with a seat. + + Each wl_keyboard has the following logical state: + + - an active surface (possibly null), + - the keys currently logically down, + - the active modifiers, + - the active group. + + By default, the active surface is null, the keys currently logically down + are empty, the active modifiers and the active group are 0. @@ -2458,10 +2468,15 @@ The compositor must send the wl_keyboard.modifiers event after this event. + + In the wl_keyboard logical state, this event sets the active surface to + the surface argument and the keys currently logically down to the keys + in the keys argument. The compositor must not send this event if the + wl_keyboard already had an active surface immediately before this event. - + @@ -2472,10 +2487,10 @@ The leave notification is sent before the enter notification for the new focus. - After this event client must assume that no keys are pressed, - it must stop key repeating if there's some going on and until - it receives the next wl_keyboard.modifiers event, the client - must also assume no modifiers are active. + In the wl_keyboard logical state, this event resets all values to their + defaults. The compositor must not send this event if the active surface + of the wl_keyboard was not equal to the surface argument immediately + before this event. @@ -2501,8 +2516,14 @@ If this event produces a change in modifiers, then the resulting wl_keyboard.modifiers event must be sent after this event. - The compositor must not send this event without a surface of the client - having keyboard focus. + In the wl_keyboard logical state, this event adds the key to the keys + currently logically down (if the state argument is pressed) or removes + the key from the keys currently logically down (if the state argument is + released). The compositor must not send this event if the wl_keyboard + did not have an active surface immediately before this event. The + compositor must not send this event if state is pressed (resp. released) + and the key was already logically down (resp. was not logically down) + immediately before this event. @@ -2522,6 +2543,9 @@ valid until it receives the next wl_keyboard.modifiers event. In order to reset the modifier state again, the compositor can send a wl_keyboard.modifiers event with no pressed modifiers. + + In the wl_keyboard logical state, this event updates the modifiers and + group. From f870320958dab7f577b16700e3cca57ea3283397 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 May 2024 16:50:40 +0200 Subject: [PATCH 1004/1152] build: bump to version 1.22.92 for the beta release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5661e7ac..8460e6db 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.22.91', + version: '1.22.92', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From 17965d99e85410f20896c8d353082bd88ba87569 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Thu, 16 May 2024 12:39:17 +0300 Subject: [PATCH 1005/1152] server: Clarify fd ownership in wl_client_create() It's unclear whether one needs to call close() if wl_client_create() fails. Hopefully this change makes it more clear. Signed-off-by: Vlad Zahorodnii --- src/wayland-server.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 2df2e6ad..0b5b13b8 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -520,6 +520,11 @@ bind_display(struct wl_client *client, struct wl_display *display); * * On failure this function sets errno accordingly and returns NULL. * + * On success, the new client object takes the ownership of the file + * descriptor. On failure, the ownership of the socket endpoint file + * descriptor is unchanged, it is the responsibility of the caller to + * perform cleanup, e.g. call close(). + * * \memberof wl_display */ WL_EXPORT struct wl_client * From 4bade6293806986500c517d3b0df571b1bf95d2d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Jun 2023 11:59:31 +0200 Subject: [PATCH 1006/1152] server: document wl_display_add_socket_fd() ownership wl_socket_destroy() will close the socket. Signed-off-by: Simon Ser --- src/wayland-server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 0b5b13b8..2e185634 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1811,6 +1811,9 @@ wl_display_add_socket_auto(struct wl_display *display) * The fd must be properly set to CLOEXEC and bound to a socket file * with both bind() and listen() already called. * + * On success, the socket fd ownership is transferred to libwayland: + * libwayland will close the socket when the display is destroyed. + * * \memberof wl_display */ WL_EXPORT int From 0b1626f47346247afe09fbf65978fc237a305892 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 May 2024 18:12:41 +0200 Subject: [PATCH 1007/1152] build: bump to version 1.22.93 for the RC1 release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8460e6db..e2976afc 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.22.92', + version: '1.22.93', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From 26c419e046a70521e07b849faae901c7521d90df Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Wed, 8 May 2024 20:54:19 +0200 Subject: [PATCH 1008/1152] protocol: clarify divergence in compositor behaviour This is intended to only document the current situation. Whether further behaviour will be defined is out of scope and left for protocol v7. See: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/363 Signed-off-by: Hugo Osvaldo Barrera --- protocol/wayland.xml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 97ad2eb2..9418c62f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1514,9 +1514,15 @@ mutates the underlying buffer storage, the surface contents become undefined immediately. - If wl_surface.attach is sent with a NULL wl_buffer, or the pending - wl_buffer has been destroyed, the following wl_surface.commit will - remove the surface content. + If wl_surface.attach is sent with a NULL wl_buffer, the + following wl_surface.commit will remove the surface content. + + If a pending wl_buffer has been destroyed, the result is not specified. + Many compositors are known to remove the surface content on the following + wl_surface.commit, but this behaviour is not universal. Clients seeking to + maximise compatibility should not destroy pending buffers and should + ensure that they explicitly remove content from surfaces, even after + destroying buffers. From a156431ea66fe67d69c9fbba8a8ad34dabbab81c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 30 May 2024 20:59:51 +0200 Subject: [PATCH 1009/1152] build: bump to version 1.23.0 for the official release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e2976afc..8e28f2a2 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.22.93', + version: '1.23.0', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From 1d5772b7b9d0bbfbc27557721f62a9f805b66929 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 30 May 2024 21:07:24 +0200 Subject: [PATCH 1010/1152] build: re-open main branch for regular development Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8e28f2a2..409cc3c0 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.23.0', + version: '1.23.90', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From caaa308c0d4025928917115c98c75edf7c796cd4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 7 Jul 2024 18:21:30 +0200 Subject: [PATCH 1011/1152] scanner: extract validator function emission to helper function This function will grow in the next commit. Signed-off-by: Simon Ser --- src/scanner.c | 59 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 95524513..a4f3cc96 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1378,6 +1378,37 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface) } } +static void +emit_validator(struct interface *interface, struct enumeration *e) +{ + struct entry *entry; + + printf("/**\n" + " * @ingroup iface_%s\n" + " * Validate a %s %s value.\n" + " *\n" + " * @return true on success, false on error.\n" + " * @ref %s_%s\n" + " */\n" + "static inline bool\n" + "%s_%s_is_valid(uint32_t value, uint32_t version) {\n" + " switch (value) {\n", + interface->name, interface->name, e->name, + interface->name, e->name, + interface->name, e->name); + wl_list_for_each(entry, &e->entry_list, link) { + printf(" case %s%s_%s_%s:\n" + " return version >= %d;\n", + entry->value[0] == '-' ? "(uint32_t)" : "", + interface->uppercase_name, e->uppercase_name, + entry->uppercase_name, entry->since); + } + printf(" default:\n" + " return false;\n" + " }\n" + "}\n"); +} + static void emit_enumerations(struct interface *interface, bool with_validators) { @@ -1439,32 +1470,8 @@ emit_enumerations(struct interface *interface, bool with_validators) } - if (with_validators) { - printf("/**\n" - " * @ingroup iface_%s\n" - " * Validate a %s %s value.\n" - " *\n" - " * @return true on success, false on error.\n" - " * @ref %s_%s\n" - " */\n" - "static inline bool\n" - "%s_%s_is_valid(uint32_t value, uint32_t version) {\n" - " switch (value) {\n", - interface->name, interface->name, e->name, - interface->name, e->name, - interface->name, e->name); - wl_list_for_each(entry, &e->entry_list, link) { - printf(" case %s%s_%s_%s:\n" - " return version >= %d;\n", - entry->value[0] == '-' ? "(uint32_t)" : "", - interface->uppercase_name, e->uppercase_name, - entry->uppercase_name, entry->since); - } - printf(" default:\n" - " return false;\n" - " }\n" - "}\n"); - } + if (with_validators) + emit_validator(interface, e); printf("#endif /* %s_%s_ENUM */\n\n", interface->uppercase_name, e->uppercase_name); From c669d992599d74af2762fbf71a4336af2e311c45 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 7 Jul 2024 18:39:51 +0200 Subject: [PATCH 1012/1152] scanner: fix validator for bitfields Bitfields are valid if the value only contains bits inside of the supported entries for the given version. Signed-off-by: Simon Ser --- src/scanner.c | 37 +++++++++---- tests/data/example-server.h | 106 ++++++++++++++++-------------------- 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index a4f3cc96..3cd05d13 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1391,22 +1391,35 @@ emit_validator(struct interface *interface, struct enumeration *e) " * @ref %s_%s\n" " */\n" "static inline bool\n" - "%s_%s_is_valid(uint32_t value, uint32_t version) {\n" - " switch (value) {\n", + "%s_%s_is_valid(uint32_t value, uint32_t version) {\n", interface->name, interface->name, e->name, interface->name, e->name, interface->name, e->name); - wl_list_for_each(entry, &e->entry_list, link) { - printf(" case %s%s_%s_%s:\n" - " return version >= %d;\n", - entry->value[0] == '-' ? "(uint32_t)" : "", - interface->uppercase_name, e->uppercase_name, - entry->uppercase_name, entry->since); + + if (e->bitfield) { + printf(" uint32_t valid = 0;\n"); + wl_list_for_each(entry, &e->entry_list, link) { + printf(" if (version >= %d)\n" + " valid |= %s_%s_%s;\n", + entry->since, + interface->uppercase_name, e->uppercase_name, + entry->uppercase_name); + } + printf(" return (value & ~valid) == 0;\n"); + } else { + printf(" switch (value) {\n"); + wl_list_for_each(entry, &e->entry_list, link) { + printf(" case %s%s_%s_%s:\n" + " return version >= %d;\n", + entry->value[0] == '-' ? "(uint32_t)" : "", + interface->uppercase_name, e->uppercase_name, + entry->uppercase_name, entry->since); + } + printf(" default:\n" + " return false;\n" + " }\n"); } - printf(" default:\n" - " return false;\n" - " }\n" - "}\n"); + printf("}\n"); } static void diff --git a/tests/data/example-server.h b/tests/data/example-server.h index b0d9226d..2fad7097 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -2396,18 +2396,16 @@ enum wl_data_device_manager_dnd_action { */ static inline bool wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: - return version >= 1; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: - return version >= 1; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: - return version >= 1; - case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK: - return version >= 1; - default: - return false; - } + uint32_t valid = 0; + if (version >= 1) + valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + if (version >= 1) + valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + if (version >= 1) + valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; + if (version >= 1) + valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + return (value & ~valid) == 0; } #endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ @@ -2560,28 +2558,26 @@ enum wl_shell_surface_resize { */ static inline bool wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case WL_SHELL_SURFACE_RESIZE_NONE: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_TOP: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_BOTTOM: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_LEFT: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_RIGHT: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: - return version >= 1; - case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: - return version >= 1; - default: - return false; - } + uint32_t valid = 0; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_NONE; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_TOP; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_LEFT; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_TOP_LEFT; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_RIGHT; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; + if (version >= 1) + valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; + return (value & ~valid) == 0; } #endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ @@ -2609,12 +2605,10 @@ enum wl_shell_surface_transient { */ static inline bool wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case WL_SHELL_SURFACE_TRANSIENT_INACTIVE: - return version >= 1; - default: - return false; - } + uint32_t valid = 0; + if (version >= 1) + valid |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE; + return (value & ~valid) == 0; } #endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ @@ -3486,16 +3480,14 @@ enum wl_seat_capability { */ static inline bool wl_seat_capability_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case WL_SEAT_CAPABILITY_POINTER: - return version >= 1; - case WL_SEAT_CAPABILITY_KEYBOARD: - return version >= 1; - case WL_SEAT_CAPABILITY_TOUCH: - return version >= 1; - default: - return false; - } + uint32_t valid = 0; + if (version >= 1) + valid |= WL_SEAT_CAPABILITY_POINTER; + if (version >= 1) + valid |= WL_SEAT_CAPABILITY_KEYBOARD; + if (version >= 1) + valid |= WL_SEAT_CAPABILITY_TOUCH; + return (value & ~valid) == 0; } #endif /* WL_SEAT_CAPABILITY_ENUM */ @@ -4567,14 +4559,12 @@ enum wl_output_mode { */ static inline bool wl_output_mode_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case WL_OUTPUT_MODE_CURRENT: - return version >= 1; - case WL_OUTPUT_MODE_PREFERRED: - return version >= 1; - default: - return false; - } + uint32_t valid = 0; + if (version >= 1) + valid |= WL_OUTPUT_MODE_CURRENT; + if (version >= 1) + valid |= WL_OUTPUT_MODE_PREFERRED; + return (value & ~valid) == 0; } #endif /* WL_OUTPUT_MODE_ENUM */ From fa1811ce3e1475a95aa39e00cfa083797661d651 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 7 Jul 2024 18:48:44 +0200 Subject: [PATCH 1013/1152] tests: add enum bitfield test Signed-off-by: Simon Ser --- tests/data/small-client-core.h | 23 +++++++++++++++++++ tests/data/small-client.h | 23 +++++++++++++++++++ tests/data/small-server-core.h | 41 ++++++++++++++++++++++++++++++++++ tests/data/small-server.h | 41 ++++++++++++++++++++++++++++++++++ tests/data/small.xml | 7 ++++++ tests/enum-validator-test.c | 15 +++++++++++++ 6 files changed, 150 insertions(+) diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h index 0e722441..03f889c8 100644 --- a/tests/data/small-client-core.h +++ b/tests/data/small-client-core.h @@ -106,6 +106,29 @@ enum intf_A_foo { #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ +#ifndef INTF_A_BAR_ENUM +#define INTF_A_BAR_ENUM +enum intf_A_bar { + /** + * this is the first + */ + INTF_A_BAR_FIRST = 0x01, + /** + * this is the second + */ + INTF_A_BAR_SECOND = 0x02, + /** + * this is the third + * @since 2 + */ + INTF_A_BAR_THIRD = 0x04, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_BAR_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_BAR_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_listener diff --git a/tests/data/small-client.h b/tests/data/small-client.h index ad435923..0d5b6055 100644 --- a/tests/data/small-client.h +++ b/tests/data/small-client.h @@ -106,6 +106,29 @@ enum intf_A_foo { #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ +#ifndef INTF_A_BAR_ENUM +#define INTF_A_BAR_ENUM +enum intf_A_bar { + /** + * this is the first + */ + INTF_A_BAR_FIRST = 0x01, + /** + * this is the second + */ + INTF_A_BAR_SECOND = 0x02, + /** + * this is the third + * @since 2 + */ + INTF_A_BAR_THIRD = 0x04, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_BAR_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_BAR_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_listener diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h index e696cde7..d4476959 100644 --- a/tests/data/small-server-core.h +++ b/tests/data/small-server-core.h @@ -133,6 +133,47 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) { } #endif /* INTF_A_FOO_ENUM */ +#ifndef INTF_A_BAR_ENUM +#define INTF_A_BAR_ENUM +enum intf_A_bar { + /** + * this is the first + */ + INTF_A_BAR_FIRST = 0x01, + /** + * this is the second + */ + INTF_A_BAR_SECOND = 0x02, + /** + * this is the third + * @since 2 + */ + INTF_A_BAR_THIRD = 0x04, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_BAR_THIRD_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + * Validate a intf_A bar value. + * + * @return true on success, false on error. + * @ref intf_A_bar + */ +static inline bool +intf_A_bar_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= INTF_A_BAR_FIRST; + if (version >= 1) + valid |= INTF_A_BAR_SECOND; + if (version >= 2) + valid |= INTF_A_BAR_THIRD; + return (value & ~valid) == 0; +} +#endif /* INTF_A_BAR_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_interface diff --git a/tests/data/small-server.h b/tests/data/small-server.h index 009d9cdd..9cafcd93 100644 --- a/tests/data/small-server.h +++ b/tests/data/small-server.h @@ -133,6 +133,47 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) { } #endif /* INTF_A_FOO_ENUM */ +#ifndef INTF_A_BAR_ENUM +#define INTF_A_BAR_ENUM +enum intf_A_bar { + /** + * this is the first + */ + INTF_A_BAR_FIRST = 0x01, + /** + * this is the second + */ + INTF_A_BAR_SECOND = 0x02, + /** + * this is the third + * @since 2 + */ + INTF_A_BAR_THIRD = 0x04, +}; +/** + * @ingroup iface_intf_A + */ +#define INTF_A_BAR_THIRD_SINCE_VERSION 2 +/** + * @ingroup iface_intf_A + * Validate a intf_A bar value. + * + * @return true on success, false on error. + * @ref intf_A_bar + */ +static inline bool +intf_A_bar_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= INTF_A_BAR_FIRST; + if (version >= 1) + valid |= INTF_A_BAR_SECOND; + if (version >= 2) + valid |= INTF_A_BAR_THIRD; + return (value & ~valid) == 0; +} +#endif /* INTF_A_BAR_ENUM */ + /** * @ingroup iface_intf_A * @struct intf_A_interface diff --git a/tests/data/small.xml b/tests/data/small.xml index ac527795..ab297490 100644 --- a/tests/data/small.xml +++ b/tests/data/small.xml @@ -58,5 +58,12 @@ + + + + + + + diff --git a/tests/enum-validator-test.c b/tests/enum-validator-test.c index 92037cff..8fb05b43 100644 --- a/tests/enum-validator-test.c +++ b/tests/enum-validator-test.c @@ -10,4 +10,19 @@ main(int argc, char *argv[]) { assert(intf_A_foo_is_valid(INTF_A_FOO_THIRD, 2)); assert(intf_A_foo_is_valid(INTF_A_FOO_NEGATIVE, 2)); + + assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST, 1)); + assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST, 2)); + assert(intf_A_bar_is_valid(INTF_A_BAR_SECOND, 1)); + assert(intf_A_bar_is_valid(INTF_A_BAR_SECOND, 2)); + assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_SECOND, 1)); + assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_SECOND, 2)); + + assert(!intf_A_bar_is_valid(INTF_A_BAR_THIRD, 1)); + assert(!intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_THIRD, 1)); + assert(intf_A_bar_is_valid(INTF_A_BAR_THIRD, 2)); + assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_THIRD, 2)); + + assert(!intf_A_bar_is_valid(0xFF, 1)); + assert(!intf_A_bar_is_valid(0xFF, 2)); } From 0cecde304f4f78b439d2edaaab6d9b543b30a5c0 Mon Sep 17 00:00:00 2001 From: meltq Date: Sun, 30 Jun 2024 22:36:11 +0530 Subject: [PATCH 1014/1152] src: switch asserts to wl_abort assert()s can be compiled away by #defining NDEBUG. Some build systems do this. Using wl_abort gives a human readable error message and it isn't compiled away. This commit closes issue #230. Signed-off-by: meltq --- src/connection.c | 3 ++- src/event-loop.c | 6 ++++-- src/wayland-client.c | 17 ++++++++++++----- src/wayland-server.c | 3 ++- src/wayland-shm.c | 23 ++++++++++++++++------- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/connection.c b/src/connection.c index 8870fd2d..fb6a4be8 100644 --- a/src/connection.c +++ b/src/connection.c @@ -75,7 +75,8 @@ struct wl_connection { static inline size_t size_pot(uint32_t size_bits) { - assert(size_bits < 8 * sizeof(size_t)); + if (!(size_bits < 8 * sizeof(size_t))) + wl_abort("Too many bits for size_t\n"); return ((size_t)1) << size_bits; } diff --git a/src/event-loop.c b/src/event-loop.c index 45222f71..f6392521 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -447,7 +447,8 @@ wl_timer_heap_disarm(struct wl_timer_heap *timers, struct wl_event_source_timer *last_end_evt; int old_source_idx; - assert(source->heap_idx >= 0); + if (!(source->heap_idx >= 0)) + wl_abort("Timer has already been disarmed\n"); old_source_idx = source->heap_idx; source->heap_idx = -1; @@ -476,7 +477,8 @@ wl_timer_heap_arm(struct wl_timer_heap *timers, struct wl_event_source_timer *source, struct timespec deadline) { - assert(source->heap_idx == -1); + if (!(source->heap_idx == -1)) + wl_abort("Timer is already armed\n"); source->deadline = deadline; timers->data[timers->active] = source; diff --git a/src/wayland-client.c b/src/wayland-client.c index 9cf27939..db5bcb58 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -235,13 +235,16 @@ wl_event_queue_init(struct wl_event_queue *queue, static void wl_proxy_unref(struct wl_proxy *proxy) { - assert(proxy->refcount > 0); + if (!(proxy->refcount > 0)) + wl_abort("Proxy requested for unref has no references\n"); if (--proxy->refcount > 0) return; /* If we get here, the client must have explicitly requested * deletion. */ - assert(proxy->flags & WL_PROXY_FLAG_DESTROYED); + if (!(proxy->flags & WL_PROXY_FLAG_DESTROYED)) + wl_abort("Proxy with no references not yet explicitly" + "destroyed\n"); free(proxy); } @@ -1172,7 +1175,8 @@ connect_to_socket(const char *name) "%s", name) + 1; } - assert(name_size > 0); + if (!(name_size > 0)) + wl_abort("Error assigning path name for socket connection\n"); if (name_size > (int)sizeof addr.sun_path) { if (!path_is_absolute) { wl_log("error: socket path \"%s/%s\" plus null terminator" @@ -2453,7 +2457,9 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) wl_list_remove(&proxy->queue_link); if (queue) { - assert(proxy->display == queue->display); + if (!(proxy->display == queue->display)) + wl_abort("Proxy and queue point to different " + "wl_displays"); proxy->queue = queue; } else { proxy->queue = &proxy->display->default_queue; @@ -2581,7 +2587,8 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper) wl_abort("Tried to destroy non-wrapper proxy with " "wl_proxy_wrapper_destroy\n"); - assert(wrapper->refcount == 1); + if (!(wrapper->refcount == 1)) + wl_abort("Expected proxy wrapper's refcount to be 1\n"); pthread_mutex_lock(&wrapper->display->mutex); diff --git a/src/wayland-server.c b/src/wayland-server.c index 2e185634..95f69e7f 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1714,7 +1714,8 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name) name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path, "%s%s%s", runtime_dir, separator, name) + 1; - assert(name_size > 0); + if (!(name_size > 0)) + wl_abort("Error assigning path name for socket address\n"); if (name_size > (int)sizeof s->addr.sun_path) { wl_log("error: socket path \"%s%s%s\" plus null terminator" " exceeds 108 bytes\n", runtime_dir, separator, name); diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 0a11736a..70685e6c 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -144,12 +144,17 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external) { if (external) { pool->external_refcount--; - assert(pool->external_refcount >= 0); + if (!(pool->external_refcount >= 0)) + wl_abort("Requested to unref an external reference to " + "pool but none found\n"); if (pool->external_refcount == 0) shm_pool_finish_resize(pool); } else { pool->internal_refcount--; - assert(pool->internal_refcount >= 0); + if (!(pool->internal_refcount >= 0)) + wl_abort("Requested to unref an internal reference to " + "pool but none found\n"); + } if (pool->internal_refcount + pool->external_refcount > 0) @@ -509,8 +514,9 @@ wl_shm_buffer_get_height(struct wl_shm_buffer *buffer) WL_EXPORT struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) { - assert(buffer->pool->internal_refcount + - buffer->pool->external_refcount); + if (!(buffer->pool->internal_refcount + + buffer->pool->external_refcount)) + wl_abort("Can't get reference to pool that has been freed\n"); buffer->pool->external_refcount++; return buffer->pool; @@ -658,8 +664,9 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer) pthread_setspecific(wl_shm_sigbus_data_key, sigbus_data); } - assert(sigbus_data->current_pool == NULL || - sigbus_data->current_pool == pool); + if (!(sigbus_data->current_pool == NULL || + sigbus_data->current_pool == pool)) + wl_abort("Incorrect pool passed for current thread\n"); sigbus_data->current_pool = pool; sigbus_data->access_count++; @@ -686,7 +693,9 @@ wl_shm_buffer_end_access(struct wl_shm_buffer *buffer) return; sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); - assert(sigbus_data && sigbus_data->access_count >= 1); + if (!(sigbus_data && sigbus_data->access_count >= 1)) + wl_abort("sigbus_data is NULL or wl_shm_buffer_begin_access " + "wasn't called before\n"); if (--sigbus_data->access_count == 0) { if (sigbus_data->fallback_mapping_used) { From f6f0a3cdec1c23c0adfe1deb9c53e8fdbb998ea4 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Fri, 26 Jul 2024 16:35:15 +0200 Subject: [PATCH 1015/1152] client: Handle proxies with no queue wl_proxy_get_queue can return NULL if the queue of the proxy was already destroyed with wl_event_queue_destroy. In this case, the queue also has no name anymore. Fixes: b42218f ("client: Allow setting names for queues") Signed-off-by: Sebastian Wick --- src/wayland-client.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index db5bcb58..a2c9ad95 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -924,10 +924,14 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, if (debug_client) { struct wl_event_queue *queue; + const char *queue_name = NULL; queue = wl_proxy_get_queue(proxy); + if (queue) + queue_name = wl_event_queue_get_name(queue); + wl_closure_print(closure, &proxy->object, true, false, NULL, - wl_event_queue_get_name(queue)); + queue_name); } if (wl_closure_send(closure, proxy->display->connection)) { From a6a4e081da12140ffe1881d83be0981966ba6daf Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 29 Jun 2024 15:05:00 +0300 Subject: [PATCH 1016/1152] Put WL_DEPRECATED in front of the function declarations This fixes the following clang error when using C23: ../src/wayland-server-core.h:680:41: error: 'deprecated' attribute cannot be applied to types 680 | int32_t stride, uint32_t format) WL_DEPRECATED; | ^ ../src/wayland-util.h:52:25: note: expanded from macro 'WL_DEPRECATED' 52 | #define WL_DEPRECATED [[deprecated]] | ^ Signed-off-by: Kirill Primak --- src/wayland-server-core.h | 3 ++- src/wayland-server.c | 15 ++++++++++----- src/wayland-server.h | 15 ++++++++++----- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 63d0f02d..fb900a91 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -674,10 +674,11 @@ wl_display_init_shm(struct wl_display *display); uint32_t * wl_display_add_shm_format(struct wl_display *display, uint32_t format); +WL_DEPRECATED struct wl_shm_buffer * wl_shm_buffer_create(struct wl_client *client, uint32_t id, int32_t width, int32_t height, - int32_t stride, uint32_t format) WL_DEPRECATED; + int32_t stride, uint32_t format); void wl_log_set_handler_server(wl_log_func_t handler); diff --git a/src/wayland-server.c b/src/wayland-server.c index 95f69e7f..2fe69afe 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -2484,9 +2484,10 @@ wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data) /** \cond */ /* Deprecated functions below. */ +WL_DEPRECATED uint32_t wl_client_add_resource(struct wl_client *client, - struct wl_resource *resource) WL_DEPRECATED; + struct wl_resource *resource); WL_EXPORT uint32_t wl_client_add_resource(struct wl_client *client, @@ -2515,11 +2516,12 @@ wl_client_add_resource(struct wl_client *client, return resource->object.id; } +WL_DEPRECATED struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, - uint32_t id, void *data) WL_DEPRECATED; + uint32_t id, void *data); WL_EXPORT struct wl_resource * wl_client_add_object(struct wl_client *client, @@ -2538,10 +2540,11 @@ wl_client_add_object(struct wl_client *client, return resource; } +WL_DEPRECATED struct wl_resource * wl_client_new_object(struct wl_client *client, const struct wl_interface *interface, - const void *implementation, void *data) WL_DEPRECATED; + const void *implementation, void *data); WL_EXPORT struct wl_resource * wl_client_new_object(struct wl_client *client, @@ -2600,10 +2603,11 @@ wl_client_get_user_data(struct wl_client *client) return client->data; } +WL_DEPRECATED struct wl_global * wl_display_add_global(struct wl_display *display, const struct wl_interface *interface, - void *data, wl_global_bind_func_t bind) WL_DEPRECATED; + void *data, wl_global_bind_func_t bind); WL_EXPORT struct wl_global * wl_display_add_global(struct wl_display *display, @@ -2613,9 +2617,10 @@ wl_display_add_global(struct wl_display *display, return wl_global_create(display, interface, interface->version, data, bind); } +WL_DEPRECATED void wl_display_remove_global(struct wl_display *display, - struct wl_global *global) WL_DEPRECATED; + struct wl_global *global); WL_EXPORT void wl_display_remove_global(struct wl_display *display, struct wl_global *global) diff --git a/src/wayland-server.h b/src/wayland-server.h index 1be565f2..48fab1dd 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -70,30 +70,35 @@ struct wl_resource { void *data; }; +WL_DEPRECATED uint32_t wl_client_add_resource(struct wl_client *client, - struct wl_resource *resource) WL_DEPRECATED; + struct wl_resource *resource); +WL_DEPRECATED struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, - uint32_t id, void *data) WL_DEPRECATED; + uint32_t id, void *data); +WL_DEPRECATED struct wl_resource * wl_client_new_object(struct wl_client *client, const struct wl_interface *interface, - const void *implementation, void *data) WL_DEPRECATED; + const void *implementation, void *data); +WL_DEPRECATED struct wl_global * wl_display_add_global(struct wl_display *display, const struct wl_interface *interface, void *data, - wl_global_bind_func_t bind) WL_DEPRECATED; + wl_global_bind_func_t bind); +WL_DEPRECATED void wl_display_remove_global(struct wl_display *display, - struct wl_global *global) WL_DEPRECATED; + struct wl_global *global); #endif From 64248963d31395b373e095972f46f61fb95bf462 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 23 May 2024 19:25:05 +0300 Subject: [PATCH 1017/1152] server: add wl_resource_post_error() docs Signed-off-by: Kirill Primak --- src/wayland-server-core.h | 1 - src/wayland-server.c | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index fb900a91..26c527ef 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -550,7 +550,6 @@ void wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args); -/* msg is a printf format string, variable args are its args. */ void wl_resource_post_error(struct wl_resource *resource, uint32_t code, const char *msg, ...) WL_PRINTF(3, 4); diff --git a/src/wayland-server.c b/src/wayland-server.c index 2fe69afe..c54a6d64 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -313,6 +313,15 @@ wl_resource_post_error_vargs(struct wl_resource *resource, } +/** Post a protocol error + * + * \param resource The resource object + * \param code The error code + * \param msg The error message format string + * \param ... The format string arguments + * + * \memberof wl_resource + */ WL_EXPORT void wl_resource_post_error(struct wl_resource *resource, uint32_t code, const char *msg, ...) From 65454cf7db29933d4931dfbe14461a59cc64944d Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 23 May 2024 19:25:40 +0300 Subject: [PATCH 1018/1152] server: expose wl_resource_post_error_vargs() Signed-off-by: Kirill Primak --- src/wayland-server-core.h | 4 ++++ src/wayland-server.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 26c527ef..b1baa25f 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -550,6 +550,10 @@ void wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args); +void +wl_resource_post_error_vargs(struct wl_resource *resource, + uint32_t code, const char *msg, va_list argp); + void wl_resource_post_error(struct wl_resource *resource, uint32_t code, const char *msg, ...) WL_PRINTF(3, 4); diff --git a/src/wayland-server.c b/src/wayland-server.c index c54a6d64..5ea9101b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -288,7 +288,16 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...) wl_resource_queue_event_array(resource, opcode, args); } -static void +/** Post a protocol error + * + * \param resource The resource object + * \param code The error code + * \param msg The error message format string + * \param argp The format string argument list + * + * \memberof wl_resource + */ +WL_EXPORT void wl_resource_post_error_vargs(struct wl_resource *resource, uint32_t code, const char *msg, va_list argp) { @@ -310,7 +319,6 @@ wl_resource_post_error_vargs(struct wl_resource *resource, wl_resource_post_event(client->display_resource, WL_DISPLAY_ERROR, resource, code, buffer); client->error = true; - } /** Post a protocol error From 2bbd80c8df129ee6810f6ec6d8d379ed3190760b Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 23 Apr 2024 19:17:22 +0200 Subject: [PATCH 1019/1152] doc: Require strings to be UTF-8 Nothing checks this yet but this gives us the opportunity to do so when we want. Signed-off-by: Sebastian Wick --- doc/publican/sources/Protocol.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 89d76d8e..38243fa7 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -150,9 +150,9 @@ Starts with an unsigned 32-bit length (including null terminator), - followed by the string contents, including terminating null byte, - then padding to a 32-bit boundary. A null value is represented - with a length of 0. + followed by the UTF-8 encoded string contents, including + terminating null byte, then padding to a 32-bit boundary. A null + value is represented with a length of 0. From 58bb6c721126c12ab644bee557bef6825562440a Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 16 Jul 2024 06:31:13 -0500 Subject: [PATCH 1020/1152] src: Finish assert() clean-up From cleanup commit 0cecde304: assert()s can be compiled away by #defining NDEBUG. Some build systems do this. Using wl_abort gives a human readable error message and it isn't compiled away. That commit missed one final assert, presumably due to missing it with grep because of a coding style issue. Fix that up, and remove inclusion of as appropriate. Signed-off-by: Derek Foreman --- cursor/convert_font.c | 1 - src/connection.c | 1 - src/event-loop.c | 1 - src/wayland-client.c | 1 - src/wayland-server.c | 4 ++-- src/wayland-shm.c | 1 - 6 files changed, 2 insertions(+), 7 deletions(-) diff --git a/cursor/convert_font.c b/cursor/convert_font.c index 74e45fbc..77e34c20 100644 --- a/cursor/convert_font.c +++ b/cursor/convert_font.c @@ -29,7 +29,6 @@ * http://fontforge.org/pcf-format.html */ -#include #include #include #include diff --git a/src/connection.c b/src/connection.c index fb6a4be8..e1b751ac 100644 --- a/src/connection.c +++ b/src/connection.c @@ -26,7 +26,6 @@ #define _GNU_SOURCE -#include #include #include #include diff --git a/src/event-loop.c b/src/event-loop.c index f6392521..51c9b9d0 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -23,7 +23,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/src/wayland-client.c b/src/wayland-client.c index a2c9ad95..f7d38d4b 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/src/wayland-server.c b/src/wayland-server.c index 5ea9101b..1d6be3ec 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -1534,7 +1533,8 @@ wl_display_terminate(struct wl_display *display) display->run = false; ret = write(display->terminate_efd, &terminate, sizeof(terminate)); - assert (ret >= 0 || errno == EAGAIN); + if (ret < 0 && errno != EAGAIN) + wl_abort("Write failed at shutdown\n"); } WL_EXPORT void diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 70685e6c..87917dad 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include From efa648056a1f2574708ec1a36a5f23733dd8c063 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 9 Aug 2024 22:14:10 +0200 Subject: [PATCH 1021/1152] ci: use detached MR pipelines See the freedesktop wiki [1]. This allows external contributors to have CI run properly. [1]: https://gitlab.freedesktop.org/freedesktop/freedesktop/-/wikis/GitLab-CI#for-project-developers Signed-off-by: Simon Ser --- .gitlab-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7dc7e33f..079ad8ba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -62,6 +62,13 @@ stages: - "Build and test" - "Other build configurations" +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS + when: never + - if: $CI_COMMIT_BRANCH + .ci-rules: rules: - when: on_success From 5b692b50b9e3d379005633d4ac20068d2069849d Mon Sep 17 00:00:00 2001 From: Fangzhou Ge Date: Wed, 7 Aug 2024 18:21:20 +0000 Subject: [PATCH 1022/1152] client: Log the object and methods when marshalling or sending fails The log that appears before a display_error can be captured as crash signature. Useful to know what it is. This is cherry-picked from chromium https://crrev.com/c/4697877 Signed-off-by: Fangzhou Ge --- src/wayland-client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index f7d38d4b..2f6e00c2 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -916,7 +916,9 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, closure = wl_closure_marshal(&proxy->object, opcode, args, message); if (closure == NULL) { - wl_log("Error marshalling request: %s\n", strerror(errno)); + wl_log("Error marshalling request for %s.%s: %s\n", + proxy->object.interface->name, message->name, + strerror(errno)); display_fatal_error(proxy->display, errno); goto err_unlock; } @@ -934,7 +936,9 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, } if (wl_closure_send(closure, proxy->display->connection)) { - wl_log("Error sending request: %s\n", strerror(errno)); + wl_log("Error sending request for %s.%s: %s\n", + proxy->object.interface->name, message->name, + strerror(errno)); display_fatal_error(proxy->display, errno); } From 0239b082b9d312275ce1112b61d795072596ce2d Mon Sep 17 00:00:00 2001 From: Joaquim Monteiro Date: Fri, 31 May 2024 02:57:29 +0100 Subject: [PATCH 1023/1152] meson: Fix use of install_data() without specifying install_dir This was broken (when in a subproject) before Meson 1.3.0, and so Meson warns against this unless the project targets 1.3.0 or newer. Signed-off-by: Joaquim Monteiro --- meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 409cc3c0..6b05bb52 100644 --- a/meson.build +++ b/meson.build @@ -131,7 +131,9 @@ if get_option('scanner') 'wayland-scanner.mk', 'protocol/wayland.xml', 'protocol/wayland.dtd', - ]) + ], + install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'wayland'), + ) install_data( [ 'wayland-scanner.m4' ], From 6c4a695045155583a99f3fbce7bb745f79c2e726 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Wed, 24 Jul 2024 21:20:12 -0400 Subject: [PATCH 1024/1152] connection: Reject strings containing NUL bytes libwayland cannot construct these messages as it uses strlen() to determine string lengths. libwayland is also guaranteed to misinterpret these messages, since message handlers only get a pointer and no length. Therefore, reject strings containing NUL bytes. Also remove a redundant check from the unmarshalling code. The zero-length case has already been checked for. Signed-off-by: Demi Marie Obenour --- doc/publican/sources/Protocol.xml | 3 ++- src/connection.c | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 38243fa7..692f17eb 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -152,7 +152,8 @@ Starts with an unsigned 32-bit length (including null terminator), followed by the UTF-8 encoded string contents, including terminating null byte, then padding to a 32-bit boundary. A null - value is represented with a length of 0. + value is represented with a length of 0. Interior null bytes are + not permitted. diff --git a/src/connection.c b/src/connection.c index e1b751ac..6b28d21d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -975,7 +975,7 @@ wl_connection_demarshal(struct wl_connection *connection, s = (char *) p; - if (length > 0 && s[length - 1] != '\0') { + if (s[length - 1] != '\0') { wl_log("string not nul-terminated, " "message %s(%s)\n", message->name, message->signature); @@ -983,6 +983,14 @@ wl_connection_demarshal(struct wl_connection *connection, goto err; } + if (strlen(s) != length - 1) { + wl_log("string has embedded nul at offset %zu, " + "message %s(%s)\n", strlen(s), + message->name, message->signature); + errno = EINVAL; + goto err; + } + closure->args[i].s = s; p = next; break; From 7c6259e9ad7562d824b024975b80e471b365d5fc Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 6 Sep 2024 13:28:07 +0200 Subject: [PATCH 1025/1152] protocol: clients should not emulate key-press events on enter The previous change introducing the logical state caused some confusion. Clarify that most application should not use the list of pressed keys. Signed-off-by: Julian Orth --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 9418c62f..3b279a0b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -2479,6 +2479,9 @@ the surface argument and the keys currently logically down to the keys in the keys argument. The compositor must not send this event if the wl_keyboard already had an active surface immediately before this event. + + Clients should not use the list of pressed keys to emulate key-press + events. The order of keys in the list is unspecified. From 1b0d45e9c6bc05399092f50b6c27bcdb43869e58 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Wed, 21 Feb 2024 21:43:36 +0000 Subject: [PATCH 1026/1152] Add wl_keyboard key repeat events This allows the compositor to take over the responsibility of repeating keys. Signed-off-by: Andri Yngvason --- protocol/wayland.xml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 3b279a0b..e0a67380 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1880,7 +1880,7 @@ - + A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a @@ -2013,7 +2013,7 @@ - + The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus @@ -2426,7 +2426,7 @@ - + The wl_keyboard interface represents one or more keyboards associated with a seat. @@ -2508,9 +2508,18 @@ Describes the physical state of a key that produced the key event. + + Since version 10, the key can be in a "repeated" pseudo-state which + means the same as "pressed", but is used to signal repetition in the + key event. + + The key may only enter the repeated state after entering the pressed + state and before entering the released state. This event may be + generated multiple times while the key is down. + @@ -2533,6 +2542,11 @@ compositor must not send this event if state is pressed (resp. released) and the key was already logically down (resp. was not logically down) immediately before this event. + + Since version 10, compositors may send key events with the "repeated" + key state when a wl_keyboard.repeat_info event with a rate argument of + 0 has been received. This allows the compositor to take over the + responsibility of key repetition. @@ -2593,7 +2607,7 @@ - + The wl_touch interface represents a touchscreen associated with a seat. From 38f91fe6adb1c4e6347dc34111e17514dac4a439 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 19 Oct 2023 16:34:26 +0200 Subject: [PATCH 1027/1152] protocol: document that wl_surface.offset is role-specific This request doesn't make sense for all surface roles. For instance, for maximized/tiled/fullscreen xdg_toplevel, for xdg_popup, for layer-shell surfaces, etc. Signed-off-by: Simon Ser --- protocol/wayland.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index e0a67380..cd089e1b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1832,6 +1832,9 @@ x and y, combined with the new surface size define in which directions the surface's size changes. + The exact semantics of wl_surface.offset are role-specific. Refer to + the documentation of specific roles for more information. + Surface location offset is double-buffered state, see wl_surface.commit. From f67db75ec118f6ec64e60113dbdecb20b4ea1abd Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Fri, 18 Oct 2024 10:25:21 +0800 Subject: [PATCH 1028/1152] cursor: add check to ensure wl_shm_create_pool succeeded Signed-off-by: YaoBing Xiao --- cursor/wayland-cursor.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 156f0a80..636f5166 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -68,11 +68,16 @@ shm_pool_create(struct wl_shm *shm, int size) goto err_close; pool->pool = wl_shm_create_pool(shm, pool->fd, size); + if (!pool->pool) + goto err_unmap; + pool->size = size; pool->used = 0; return pool; +err_unmap: + munmap(pool->data, size); err_close: close(pool->fd); err_free: From 10df74c240d3cff4bd56bf17ebfc1a54883e00f5 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 24 Apr 2024 16:17:58 +0200 Subject: [PATCH 1029/1152] protocol: add wl_fixes interface This commit describes a new wl_fixes interface that can be used to destroy wl_registry objects. Users of libwayland-client should use it as follows: - call wl_fixes_destroy_registry(registry) - call wl_registry_destroy(registry) Users of libwayland-server should, in their implementation of the request, call wl_resource_destroy(registry). It should be similar in other protocol implementations. Signed-off-by: Julian Orth --- protocol/wayland.xml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index cd089e1b..f32918e9 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -3265,4 +3265,31 @@ + + + This global fixes problems with other core-protocol interfaces that + cannot be fixed in these interfaces themselves. + + + + + + + + + This request destroys a wl_registry object. + + The client should no longer use the wl_registry after making this + request. + + The compositor will emit a wl_display.delete_id event with the object ID + of the registry and will no longer emit any events on the registry. The + client should re-use the object ID once it receives the + wl_display.delete_id event. + + + + + From 4273a5edc862bd5f620ad0c7f11d20cd040e005c Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Wed, 24 Jul 2024 21:18:40 -0400 Subject: [PATCH 1030/1152] connection: Avoid undefined pointer arithmetic Creating a pointer that is more than one element past the end of an array is undefined behavior, even if the pointer is not dereferenced. Avoid this undefined behavior by using `p >= end` instead of `p + 1 > end` and `SOMETHING > end - p` instead of `p + SOMETHING > end`. Signed-off-by: Demi Marie Obenour --- src/connection.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/connection.c b/src/connection.c index 6b28d21d..1177d667 100644 --- a/src/connection.c +++ b/src/connection.c @@ -928,7 +928,7 @@ wl_connection_demarshal(struct wl_connection *connection, for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); - if (arg.type != WL_ARG_FD && p + 1 > end) { + if (arg.type != WL_ARG_FD && p >= end) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, @@ -1351,7 +1351,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, if (arg.type == WL_ARG_FD) continue; - if (p + 1 > end) + if (p >= end) goto overflow; switch (arg.type) { @@ -1379,7 +1379,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, size = strlen(closure->args[i].s) + 1; *p++ = size; - if (p + div_roundup(size, sizeof *p) > end) + if (div_roundup(size, sizeof *p) > (uint32_t)(end - p)) goto overflow; memcpy(p, closure->args[i].s, size); @@ -1394,7 +1394,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, size = closure->args[i].a->size; *p++ = size; - if (p + div_roundup(size, sizeof *p) > end) + if (div_roundup(size, sizeof *p) > (uint32_t)(end - p)) goto overflow; if (size != 0) From 290c36bc507d7d2f391b7eb1dc8fd9841c37e770 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Mon, 5 Aug 2024 12:49:49 -0400 Subject: [PATCH 1031/1152] tests: Avoid calling function with wrong type Calling a function with the wrong type is immediate undefined behavior, even if the ABI says it should be harmless. UBSAN picks it up immediately, and any decent control-flow integrity mechanism will as well. Signed-off-by: Demi Marie Obenour --- tests/display-test.c | 18 +++++++++--------- tests/test-compositor.c | 2 +- tests/test-compositor.h | 14 +++++++++++++- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/display-test.c b/tests/display-test.c index c2def444..89606c73 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -924,7 +924,7 @@ TEST(versions) } static void -check_error_on_destroyed_object(void *data) +check_error_on_destroyed_object(void) { struct client *c; struct wl_seat *seat; @@ -1043,7 +1043,7 @@ TEST(filtered_global_is_hidden) 1, d, bind_data_offer); wl_display_set_global_filter(d->wl_display, global_filter, NULL); - client_create_noarg(d, get_globals); + client_create(d, get_globals, NULL); display_run(d); wl_global_destroy(g); @@ -1052,13 +1052,13 @@ TEST(filtered_global_is_hidden) } static void -get_dynamic_globals(void *data) +get_dynamic_globals(void) { struct client *c = client_connect(); struct wl_registry *registry; registry = wl_display_get_registry(c->wl_display); - wl_registry_add_listener(registry, ®istry_listener_filtered, data); + wl_registry_add_listener(registry, ®istry_listener_filtered, NULL); wl_display_roundtrip(c->wl_display); /* Wait for the server to create a new global */ @@ -1206,7 +1206,7 @@ static const struct wl_registry_listener zombie_fd_registry_listener = { }; static void -zombie_client(void *data) +zombie_client(void) { struct client *c = client_connect(); struct wl_registry *registry; @@ -1376,7 +1376,7 @@ static const struct wl_registry_listener double_zombie_fd_registry_listener = { }; static void -double_zombie_client(void *data) +double_zombie_client(void) { struct client *c = client_connect(); struct wl_registry *registry; @@ -1436,7 +1436,7 @@ static const struct wl_registry_listener bind_interface_mismatch_registry_listen }; static void -registry_bind_interface_mismatch_client(void *data) +registry_bind_interface_mismatch_client(void) { struct client *c = client_connect(); struct wl_registry *registry; @@ -1598,7 +1598,7 @@ static const struct wl_registry_listener global_remove_before_registry_listener }; static void -global_remove_before_client(void *data) +global_remove_before_client(void) { struct client *c = client_connect(); struct wl_registry *registry; @@ -1648,7 +1648,7 @@ static const struct wl_registry_listener global_remove_after_registry_listener = }; static void -global_remove_after_client(void *data) +global_remove_after_client(void) { struct client *c = client_connect(); struct wl_registry *registry; diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 8648fb69..8ec0631b 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -507,7 +507,7 @@ static const struct wl_registry_listener registry_listener = NULL }; -struct client *client_connect() +struct client *client_connect(void) { struct wl_registry *reg; struct client *c = calloc(1, sizeof *c); diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 3fb390c2..662a81c3 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -118,5 +118,17 @@ struct client_info *client_create_with_name(struct display *d, void *data, const char *name); #define client_create(d, c, data) client_create_with_name((d), (c), data, (#c)) +static inline void noarg_cb(void *data) +{ + void (*cb)(void) = data; + cb(); +} +static inline struct client_info *client_create_with_name_noarg(struct display *d, + void (*client_main)(void), + const char *name) +{ + return client_create_with_name(d, noarg_cb, client_main, name); +} + #define client_create_noarg(d, c) \ - client_create_with_name((d), (void(*)(void *)) (c), NULL, (#c)) + client_create_with_name_noarg((d), (c), (#c)) From 9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Mon, 5 Aug 2024 12:59:21 -0400 Subject: [PATCH 1032/1152] connection: Fix wrong format string Prevents undefined behavior if there is not enough space in the buffer for a queued message. Signed-off-by: Demi Marie Obenour --- src/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index 1177d667..34495211 100644 --- a/src/connection.c +++ b/src/connection.c @@ -260,7 +260,7 @@ ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count) * allowed). */ if (net_size > size_pot(size_bits)) { - wl_log("Data too big for buffer (%d + %zd > %zd).\n", + wl_log("Data too big for buffer (%zu + %zu > %zu).\n", ring_buffer_size(b), count, size_pot(size_bits)); errno = E2BIG; return -1; From f246e619d17deb92f414315d1747a9b7aca659b9 Mon Sep 17 00:00:00 2001 From: Haihua Hu Date: Mon, 6 Jan 2025 21:55:37 +0900 Subject: [PATCH 1033/1152] util: reduce error of wl_fixed_from_double() when cast double to fixed pointer, there will be big error, eg 1919.9998 to 1919. Call round before cast to get nearest value 1920 of 1919.9998 Signed-off-by: Haihua Hu --- src/wayland-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 929a34f3..4edec8b0 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -635,7 +635,7 @@ wl_fixed_to_double(wl_fixed_t f) static inline wl_fixed_t wl_fixed_from_double(double d) { - return (wl_fixed_t) (d * 256.0); + return (wl_fixed_t) (round(d * 256.0)); } /** From 597a6b94f52d6f875410593e09a4bb3adaefbea5 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 21 Jan 2025 16:20:05 +0000 Subject: [PATCH 1034/1152] ci: Update ci-templates This includes an explicit way to specify the container architecture, which fixes our rebuilds on ARMv7. Signed-off-by: Daniel Stone --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 079ad8ba..eb6fb0b4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ include: # API changes. If you need new features from ci-templates you must bump # this to the current SHA you require from the ci-templates repo, however # be aware that you may need to account for API changes when doing so. - ref: b791bd48996e3ced9ca13f1c5ee82be8540b8adb + ref: f210ea84576f756816da37908771edcee14ef7e6 file: - '/templates/debian.yml' - '/templates/freebsd.yml' @@ -82,7 +82,7 @@ workflow: FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson~=0.57.2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2024-03-28.2" + FDO_DISTRIBUTION_TAG: "2025-01-21.1" .debian-x86_64: extends: @@ -101,6 +101,7 @@ workflow: - .os-debian variables: BUILD_ARCH: "armv7" + FDO_DISTRIBUTION_PLATFORM: "linux/arm/v7" # Does not inherit .ci-rules as we only want it to run in MR context. @@ -154,7 +155,6 @@ armv7-debian-container_prep: stage: "Base container" variables: GIT_STRATEGY: none - FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION" # Core build environment. From bdba21ec92bf582f606806ad5fd15107979d8947 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Thu, 6 Jul 2023 18:18:37 +0200 Subject: [PATCH 1035/1152] server: add const qualifier to function arguments where possible Makes it possible to e.g. `call wl_client_get_credentials` with a `const struct wl_client *` from a global filter callback. Signed-off-by: Sebastian Wick --- src/wayland-server-core.h | 19 ++++++++++--------- src/wayland-server.c | 10 +++++----- src/wayland-shm.c | 8 ++++---- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index b1baa25f..15c3b762 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -227,7 +227,7 @@ typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, uint32_t version, uint32_t id); uint32_t -wl_display_get_serial(struct wl_display *display); +wl_display_get_serial(const struct wl_display *display); uint32_t wl_display_next_serial(struct wl_display *display); @@ -324,7 +324,7 @@ void wl_client_flush(struct wl_client *client); void -wl_client_get_credentials(struct wl_client *client, +wl_client_get_credentials(const struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid); int @@ -586,7 +586,7 @@ void wl_resource_destroy(struct wl_resource *resource); uint32_t -wl_resource_get_id(struct wl_resource *resource); +wl_resource_get_id(const struct wl_resource *resource); struct wl_list * wl_resource_get_link(struct wl_resource *resource); @@ -607,7 +607,7 @@ void * wl_resource_get_user_data(struct wl_resource *resource); int -wl_resource_get_version(struct wl_resource *resource); +wl_resource_get_version(const struct wl_resource *resource); void wl_resource_set_destructor(struct wl_resource *resource, @@ -617,8 +617,9 @@ int wl_resource_instance_of(struct wl_resource *resource, const struct wl_interface *interface, const void *implementation); + const char * -wl_resource_get_class(struct wl_resource *resource); +wl_resource_get_class(const struct wl_resource *resource); void wl_resource_add_destroy_listener(struct wl_resource *resource, @@ -654,16 +655,16 @@ void * wl_shm_buffer_get_data(struct wl_shm_buffer *buffer); int32_t -wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer); +wl_shm_buffer_get_stride(const struct wl_shm_buffer *buffer); uint32_t -wl_shm_buffer_get_format(struct wl_shm_buffer *buffer); +wl_shm_buffer_get_format(const struct wl_shm_buffer *buffer); int32_t -wl_shm_buffer_get_width(struct wl_shm_buffer *buffer); +wl_shm_buffer_get_width(const struct wl_shm_buffer *buffer); int32_t -wl_shm_buffer_get_height(struct wl_shm_buffer *buffer); +wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer); struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer); diff --git a/src/wayland-server.c b/src/wayland-server.c index 1d6be3ec..e5805669 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -619,7 +619,7 @@ err_client: * \memberof wl_client */ WL_EXPORT void -wl_client_get_credentials(struct wl_client *client, +wl_client_get_credentials(const struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid) { if (pid) @@ -799,7 +799,7 @@ wl_resource_destroy(struct wl_resource *resource) } WL_EXPORT uint32_t -wl_resource_get_id(struct wl_resource *resource) +wl_resource_get_id(const struct wl_resource *resource) { return resource->object.id; } @@ -853,7 +853,7 @@ wl_resource_get_user_data(struct wl_resource *resource) } WL_EXPORT int -wl_resource_get_version(struct wl_resource *resource) +wl_resource_get_version(const struct wl_resource *resource) { return resource->version; } @@ -900,7 +900,7 @@ wl_resource_get_destroy_listener(struct wl_resource *resource, * \memberof wl_resource */ WL_EXPORT const char * -wl_resource_get_class(struct wl_resource *resource) +wl_resource_get_class(const struct wl_resource *resource) { return resource->object.interface->name; } @@ -1496,7 +1496,7 @@ wl_global_set_user_data(struct wl_global *global, void *data) * \memberof wl_display */ WL_EXPORT uint32_t -wl_display_get_serial(struct wl_display *display) +wl_display_get_serial(const struct wl_display *display) { return display->serial; } diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 87917dad..9b3aac61 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -445,7 +445,7 @@ wl_shm_buffer_get(struct wl_resource *resource) } WL_EXPORT int32_t -wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer) +wl_shm_buffer_get_stride(const struct wl_shm_buffer *buffer) { return buffer->stride; } @@ -479,19 +479,19 @@ wl_shm_buffer_get_data(struct wl_shm_buffer *buffer) } WL_EXPORT uint32_t -wl_shm_buffer_get_format(struct wl_shm_buffer *buffer) +wl_shm_buffer_get_format(const struct wl_shm_buffer *buffer) { return buffer->format; } WL_EXPORT int32_t -wl_shm_buffer_get_width(struct wl_shm_buffer *buffer) +wl_shm_buffer_get_width(const struct wl_shm_buffer *buffer) { return buffer->width; } WL_EXPORT int32_t -wl_shm_buffer_get_height(struct wl_shm_buffer *buffer) +wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer) { return buffer->height; } From 37469d5ceda49ef7551a0fe94f7886f863f76408 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 7 Feb 2024 19:00:37 +0100 Subject: [PATCH 1036/1152] timespec: Pull in timespec.h from weston Signed-off-by: Sebastian Wick --- src/timespec-util.h | 259 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 src/timespec-util.h diff --git a/src/timespec-util.h b/src/timespec-util.h new file mode 100644 index 00000000..f79969bb --- /dev/null +++ b/src/timespec-util.h @@ -0,0 +1,259 @@ +/* + * Copyright © 2014 - 2015 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TIMESPEC_UTIL_H +#define TIMESPEC_UTIL_H + +#include +#include +#include +#include + +#define NSEC_PER_SEC 1000000000 + +/* Subtract timespecs + * + * \param r[out] result: a - b + * \param a[in] operand + * \param b[in] operand + */ +static inline void +timespec_sub(struct timespec *r, + const struct timespec *a, const struct timespec *b) +{ + r->tv_sec = a->tv_sec - b->tv_sec; + r->tv_nsec = a->tv_nsec - b->tv_nsec; + if (r->tv_nsec < 0) { + r->tv_sec--; + r->tv_nsec += NSEC_PER_SEC; + } +} + +/* Add a nanosecond value to a timespec + * + * \param r[out] result: a + b + * \param a[in] base operand as timespec + * \param b[in] operand in nanoseconds + */ +static inline void +timespec_add_nsec(struct timespec *r, const struct timespec *a, int64_t b) +{ + r->tv_sec = a->tv_sec + (b / NSEC_PER_SEC); + r->tv_nsec = a->tv_nsec + (b % NSEC_PER_SEC); + + if (r->tv_nsec >= NSEC_PER_SEC) { + r->tv_sec++; + r->tv_nsec -= NSEC_PER_SEC; + } else if (r->tv_nsec < 0) { + r->tv_sec--; + r->tv_nsec += NSEC_PER_SEC; + } +} + +/* Add a millisecond value to a timespec + * + * \param r[out] result: a + b + * \param a[in] base operand as timespec + * \param b[in] operand in milliseconds + */ +static inline void +timespec_add_msec(struct timespec *r, const struct timespec *a, int64_t b) +{ + timespec_add_nsec(r, a, b * 1000000); +} + +/* Convert timespec to nanoseconds + * + * \param a timespec + * \return nanoseconds + */ +static inline int64_t +timespec_to_nsec(const struct timespec *a) +{ + return (int64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec; +} + +/* Subtract timespecs and return result in nanoseconds + * + * \param a[in] operand + * \param b[in] operand + * \return to_nanoseconds(a - b) + */ +static inline int64_t +timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b) +{ + struct timespec r; + timespec_sub(&r, a, b); + return timespec_to_nsec(&r); +} + +/* Convert timespec to milliseconds + * + * \param a timespec + * \return milliseconds + * + * Rounding to integer milliseconds happens always down (floor()). + */ +static inline int64_t +timespec_to_msec(const struct timespec *a) +{ + return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +} + +/* Subtract timespecs and return result in milliseconds + * + * \param a[in] operand + * \param b[in] operand + * \return to_milliseconds(a - b) + */ +static inline int64_t +timespec_sub_to_msec(const struct timespec *a, const struct timespec *b) +{ + return timespec_sub_to_nsec(a, b) / 1000000; +} + +/* Convert timespec to microseconds + * + * \param a timespec + * \return microseconds + * + * Rounding to integer microseconds happens always down (floor()). + */ +static inline int64_t +timespec_to_usec(const struct timespec *a) +{ + return (int64_t)a->tv_sec * 1000000 + a->tv_nsec / 1000; +} + +/* Convert timespec to protocol data + * + * \param a timespec + * \param tv_sec_hi[out] the high bytes of the seconds part + * \param tv_sec_lo[out] the low bytes of the seconds part + * \param tv_nsec[out] the nanoseconds part + * + * The input timespec must be normalized (the nanoseconds part should + * be less than 1 second) and non-negative. + */ +static inline void +timespec_to_proto(const struct timespec *a, uint32_t *tv_sec_hi, + uint32_t *tv_sec_lo, uint32_t *tv_nsec) +{ + assert(a->tv_sec >= 0); + assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC); + + uint64_t sec64 = a->tv_sec; + + *tv_sec_hi = sec64 >> 32; + *tv_sec_lo = sec64 & 0xffffffff; + *tv_nsec = a->tv_nsec; +} + +/* Convert nanoseconds to timespec + * + * \param a timespec + * \param b nanoseconds + */ +static inline void +timespec_from_nsec(struct timespec *a, int64_t b) +{ + a->tv_sec = b / NSEC_PER_SEC; + a->tv_nsec = b % NSEC_PER_SEC; +} + +/* Convert microseconds to timespec + * + * \param a timespec + * \param b microseconds + */ +static inline void +timespec_from_usec(struct timespec *a, int64_t b) +{ + timespec_from_nsec(a, b * 1000); +} + +/* Convert milliseconds to timespec + * + * \param a timespec + * \param b milliseconds + */ +static inline void +timespec_from_msec(struct timespec *a, int64_t b) +{ + timespec_from_nsec(a, b * 1000000); +} + +/* Convert protocol data to timespec + * + * \param a[out] timespec + * \param tv_sec_hi the high bytes of seconds part + * \param tv_sec_lo the low bytes of seconds part + * \param tv_nsec the nanoseconds part + */ +static inline void +timespec_from_proto(struct timespec *a, uint32_t tv_sec_hi, + uint32_t tv_sec_lo, uint32_t tv_nsec) +{ + a->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo; + a->tv_nsec = tv_nsec; +} + +/* Check if a timespec is zero + * + * \param a timespec + * \return whether the timespec is zero + */ +static inline bool +timespec_is_zero(const struct timespec *a) +{ + return a->tv_sec == 0 && a->tv_nsec == 0; +} + +/* Check if two timespecs are equal + * + * \param a[in] timespec to check + * \param b[in] timespec to check + * \return whether timespecs a and b are equal + */ +static inline bool +timespec_eq(const struct timespec *a, const struct timespec *b) +{ + return a->tv_sec == b->tv_sec && + a->tv_nsec == b->tv_nsec; +} + +/* Convert milli-Hertz to nanoseconds + * + * \param mhz frequency in mHz, not zero + * \return period in nanoseconds + */ +static inline int64_t +millihz_to_nsec(uint32_t mhz) +{ + assert(mhz > 0); + return 1000000000000LL / mhz; +} + +#endif /* TIMESPEC_UTIL_H */ From 9d5de6062ba82a56d25d8a53ccace3afecbf50e5 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 7 Feb 2024 18:51:39 +0100 Subject: [PATCH 1037/1152] timespec: Pull in timespec_after and timespec_add from mesa Signed-off-by: Sebastian Wick --- src/timespec-util.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/timespec-util.h b/src/timespec-util.h index f79969bb..d37568d2 100644 --- a/src/timespec-util.h +++ b/src/timespec-util.h @@ -256,4 +256,38 @@ millihz_to_nsec(uint32_t mhz) return 1000000000000LL / mhz; } +/** + * Checks whether a timespec value is after another + * + * \param a[in] timespec to compare + * \param b[in] timespec to compare + * \return whether a is after b + */ +static inline bool +timespec_after(const struct timespec *a, const struct timespec *b) +{ + return (a->tv_sec == b->tv_sec) ? + (a->tv_nsec > b->tv_nsec) : + (a->tv_sec > b->tv_sec); +} + +/** + * Add timespecs + * + * \param r[out] result: a + b + * \param a[in] operand + * \param b[in] operand + */ +static inline void +timespec_add(struct timespec *r, + const struct timespec *a, const struct timespec *b) +{ + r->tv_sec = a->tv_sec + b->tv_sec; + r->tv_nsec = a->tv_nsec + b->tv_nsec; + if (r->tv_nsec > NSEC_PER_SEC) { + r->tv_sec++; + r->tv_nsec -= NSEC_PER_SEC; + } +} + #endif /* TIMESPEC_UTIL_H */ From 893e4fc46d31d1cc51c1e39481f5659a40152233 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 7 Feb 2024 18:53:16 +0100 Subject: [PATCH 1038/1152] timespec: Implement saturating timespec substraction Signed-off-by: Sebastian Wick --- src/timespec-util.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/timespec-util.h b/src/timespec-util.h index d37568d2..d3c53bd7 100644 --- a/src/timespec-util.h +++ b/src/timespec-util.h @@ -290,4 +290,22 @@ timespec_add(struct timespec *r, } } +/** + * Saturating timespec subtraction + * + * \param r[out] result: max(a - b, 0) + * \param a[in] operand + * \param b[in] operand + */ +static inline void +timespec_sub_saturate(struct timespec *r, + const struct timespec *a, const struct timespec *b) +{ + timespec_sub(r, a, b); + if (r->tv_sec < 0) { + r->tv_sec = 0; + r->tv_nsec = 0; + } +} + #endif /* TIMESPEC_UTIL_H */ From ff8b88552358b6977043db0d6ee0cac7d7abfa0c Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 7 Feb 2024 18:46:58 +0100 Subject: [PATCH 1039/1152] event-loop: Use timespec utils instead of hand-rolling our own Signed-off-by: Sebastian Wick --- src/event-loop.c | 61 ++++++------------------------------------------ 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/src/event-loop.c b/src/event-loop.c index 51c9b9d0..89294fd9 100644 --- a/src/event-loop.c +++ b/src/event-loop.c @@ -38,6 +38,7 @@ #include #include #include +#include "timespec-util.h" #include "wayland-util.h" #include "wayland-private.h" #include "wayland-server-core.h" @@ -973,57 +974,6 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop) } } -static int -timespec_to_ms(struct timespec value) -{ - return (value.tv_sec * 1000) + (value.tv_nsec / 1000000); -} - -static struct timespec -ms_to_timespec(int ms) -{ - struct timespec val; - val.tv_sec = ms / 1000; - val.tv_nsec = (ms % 1000) * 1000000; - return val; -} - -static struct timespec -timespec_normalize(struct timespec value) -{ - struct timespec result = value; - - while (result.tv_nsec >= 1000000000) { - result.tv_nsec -= 1000000000; - result.tv_sec++; - } - - while (result.tv_nsec < 0) { - result.tv_nsec += 1000000000; - result.tv_sec--; - } - - return result; -} - -static struct timespec -timespec_add(struct timespec a, struct timespec b) -{ - struct timespec result; - result.tv_sec = a.tv_sec + b.tv_sec; - result.tv_nsec = a.tv_nsec + b.tv_nsec; - return timespec_normalize(result); -} - -static struct timespec -timespec_sub(struct timespec a, struct timespec b) -{ - struct timespec result; - result.tv_sec = a.tv_sec - b.tv_sec; - result.tv_nsec = a.tv_nsec - b.tv_nsec; - return timespec_normalize(result); -} - /** Wait for events and dispatch them * * \param loop The event loop whose sources to wait for. @@ -1052,13 +1002,15 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) int i, count; bool has_timers = false; bool use_timeout = timeout > 0; - struct timespec now, end; + struct timespec now; + struct timespec deadline = {0}; + struct timespec result; wl_event_loop_dispatch_idle(loop); if (use_timeout) { clock_gettime(CLOCK_MONOTONIC, &now); - end = timespec_add(now, ms_to_timespec(timeout)); + timespec_add_msec(&deadline, &now, timeout); } while (true) { @@ -1070,7 +1022,8 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) if (use_timeout) { clock_gettime(CLOCK_MONOTONIC, &now); - timeout = timespec_to_ms(timespec_sub(end, now)); + timespec_sub(&result, &deadline, &now); + timeout = timespec_to_msec(&result); if (timeout <= 0) { /* too late */ count = 0; From ddd348da7ea0889056843cf252729185d306b7b8 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 7 Feb 2024 19:00:46 +0100 Subject: [PATCH 1040/1152] client: Add wl_display_dispatch_queue_timeout For dispatching messages on a queue with a timeout. This slightly changes the samantics of wl_display_dispatch. Previously it was possible for it to return even though there wasn't a single dispatched event. The function correctly returned 0 in this case but it is now used to indicate a timeout. Signed-off-by: Sebastian Wick --- src/wayland-client-core.h | 6 ++ src/wayland-client.c | 155 +++++++++++++++++++++++++++++--------- 2 files changed, 127 insertions(+), 34 deletions(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index a4ca4e5d..6d45dc03 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -27,6 +27,7 @@ #define WAYLAND_CLIENT_CORE_H #include +#include #include "wayland-util.h" #include "wayland-version.h" @@ -250,6 +251,11 @@ int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue); +int +wl_display_dispatch_queue_timeout(struct wl_display *display, + struct wl_event_queue *queue, + const struct timespec *timeout); + int wl_display_dispatch_queue_pending(struct wl_display *display, struct wl_event_queue *queue); diff --git a/src/wayland-client.c b/src/wayland-client.c index 2f6e00c2..a60e5673 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -45,6 +45,7 @@ #include "wayland-os.h" #include "wayland-client.h" #include "wayland-private.h" +#include "timespec-util.h" /** \cond */ @@ -1953,20 +1954,133 @@ wl_display_cancel_read(struct wl_display *display) } static int -wl_display_poll(struct wl_display *display, short int events) +wl_display_poll(struct wl_display *display, + short int events, + const struct timespec *timeout) { int ret; struct pollfd pfd[1]; + struct timespec now; + struct timespec deadline = {0}; + struct timespec result; + struct timespec *remaining_timeout = NULL; + + if (timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespec_add(&deadline, &now, timeout); + } pfd[0].fd = display->fd; pfd[0].events = events; do { - ret = poll(pfd, 1, -1); + if (timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespec_sub_saturate(&result, &deadline, &now); + remaining_timeout = &result; + } + ret = ppoll(pfd, 1, remaining_timeout, NULL); } while (ret == -1 && errno == EINTR); return ret; } +/** Dispatch events in an event queue with a timeout + * + * \param display The display context object + * \param queue The event queue to dispatch + * \param timeout A timeout describing how long the call should block trying to + * dispatch events + * \return The number of dispatched events on success, -1 on failure + * + * This function behaves identical to wl_display_dispatch_queue() except + * that it also takes a timeout and returns 0 if the timeout elapsed. + * + * Passing NULL as a timeout means an infinite timeout. An empty timespec + * causes wl_display_dispatch_queue_timeout() to return immediately even if no + * events have been dispatched. + * + * If a timeout is passed to wl_display_dispatch_queue_timeout() it is updated + * to the remaining time. + * + * \sa wl_display_dispatch_queue() + * + * \memberof wl_display + */ +WL_EXPORT int +wl_display_dispatch_queue_timeout(struct wl_display *display, + struct wl_event_queue *queue, + const struct timespec *timeout) +{ + int ret; + struct timespec now; + struct timespec deadline = {0}; + struct timespec result; + struct timespec *remaining_timeout = NULL; + + if (timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespec_add(&deadline, &now, timeout); + } + + if (wl_display_prepare_read_queue(display, queue) == -1) + return wl_display_dispatch_queue_pending(display, queue); + + while (true) { + ret = wl_display_flush(display); + + if (ret != -1 || errno != EAGAIN) + break; + + if (timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespec_sub_saturate(&result, &deadline, &now); + remaining_timeout = &result; + } + ret = wl_display_poll(display, POLLOUT, remaining_timeout); + + if (ret <= 0) { + wl_display_cancel_read(display); + return ret; + } + } + + /* Don't stop if flushing hits an EPIPE; continue so we can read any + * protocol error that may have triggered it. */ + if (ret < 0 && errno != EPIPE) { + wl_display_cancel_read(display); + return -1; + } + + while (true) { + if (timeout) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespec_sub_saturate(&result, &deadline, &now); + remaining_timeout = &result; + } + + ret = wl_display_poll(display, POLLIN, remaining_timeout); + if (ret <= 0) { + wl_display_cancel_read(display); + break; + } + + ret = wl_display_read_events(display); + if (ret == -1) + break; + + ret = wl_display_dispatch_queue_pending(display, queue); + if (ret != 0) + break; + + /* We managed to read data from the display but there is no + * complete event to dispatch yet. Try reading again. */ + if (wl_display_prepare_read_queue(display, queue) == -1) + return wl_display_dispatch_queue_pending(display, queue); + } + + return ret; +} + /** Dispatch events in an event queue * * \param display The display context object @@ -1998,8 +2112,8 @@ wl_display_poll(struct wl_display *display, short int events) * \note Since Wayland 1.5 the display has an extra queue * for its own events (i. e. delete_id). This queue is dispatched always, * no matter what queue we passed as an argument to this function. - * That means that this function can return non-0 value even when it - * haven't dispatched any event for the given queue. + * That means that this function can return even when it has not dispatched any + * event for the given queue. * * \sa wl_display_dispatch(), wl_display_dispatch_pending(), * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue() @@ -2012,37 +2126,10 @@ wl_display_dispatch_queue(struct wl_display *display, { int ret; - if (wl_display_prepare_read_queue(display, queue) == -1) - return wl_display_dispatch_queue_pending(display, queue); + ret = wl_display_dispatch_queue_timeout(display, queue, NULL); + assert(ret == -1 || ret > 0); - while (true) { - ret = wl_display_flush(display); - - if (ret != -1 || errno != EAGAIN) - break; - - if (wl_display_poll(display, POLLOUT) == -1) { - wl_display_cancel_read(display); - return -1; - } - } - - /* Don't stop if flushing hits an EPIPE; continue so we can read any - * protocol error that may have triggered it. */ - if (ret < 0 && errno != EPIPE) { - wl_display_cancel_read(display); - return -1; - } - - if (wl_display_poll(display, POLLIN) == -1) { - wl_display_cancel_read(display); - return -1; - } - - if (wl_display_read_events(display) == -1) - return -1; - - return wl_display_dispatch_queue_pending(display, queue); + return ret; } /** Dispatch pending events in an event queue From 00dcf6b32386a63055fc04817256dc71efad1800 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 7 Feb 2024 18:59:14 +0100 Subject: [PATCH 1041/1152] client: Add wl_display_dispatch_timeout A variant of wl_display_dispatch_queue_timeout for the default queue. Signed-off-by: Sebastian Wick --- src/wayland-client-core.h | 4 ++++ src/wayland-client.c | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 6d45dc03..157da431 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -251,6 +251,10 @@ int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue); +int +wl_display_dispatch_timeout(struct wl_display *display, + const struct timespec *timeout); + int wl_display_dispatch_queue_timeout(struct wl_display *display, struct wl_event_queue *queue, diff --git a/src/wayland-client.c b/src/wayland-client.c index a60e5673..8df160b4 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2081,6 +2081,15 @@ wl_display_dispatch_queue_timeout(struct wl_display *display, return ret; } +WL_EXPORT int +wl_display_dispatch_timeout(struct wl_display *display, + const struct timespec *timeout) +{ + return wl_display_dispatch_queue_timeout(display, + &display->default_queue, + timeout); +} + /** Dispatch events in an event queue * * \param display The display context object From 74f322c35a4eef1332456ce9985255df7269f82f Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 28 Jan 2025 21:24:46 +0100 Subject: [PATCH 1042/1152] tests: Add dispatch timeout tests Add tests which verify that... * wl_display_dispatch_timeout with a big enough timeout behaves the same as wl_display_dispatch * wl_display_dispatch_timeout will time out when there are no messages to dispatch Signed-off-by: Sebastian Wick --- tests/queue-test.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/tests/queue-test.c b/tests/queue-test.c index cb61a85b..7dfdd306 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -40,6 +40,7 @@ #include "wayland-server.h" #include "test-runner.h" #include "test-compositor.h" +#include "../src/timespec-util.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) @@ -571,6 +572,68 @@ client_test_queue_names(void) wl_display_disconnect(display); } +static void +dispatch_timeout_sync_callback(void *data, struct wl_callback *callback, + uint32_t serial) +{ + bool *done = data; + + *done = true; + wl_callback_destroy(callback); +} + +static const struct wl_callback_listener dispatch_timeout_sync_listener = { + dispatch_timeout_sync_callback +}; + +static void +client_test_queue_dispatch_simple(void) +{ + struct wl_display *display; + struct timespec timeout; + struct wl_callback *callback; + bool done = false; + int ret = 0; + + display = wl_display_connect(NULL); + assert(display); + + callback = wl_display_sync(display); + assert(callback != NULL); + wl_callback_add_listener(callback, &dispatch_timeout_sync_listener, &done); + + timespec_from_msec(&timeout, 1000); + + while (!done) { + ret = wl_display_dispatch_timeout(display, &timeout); + assert(ret > 0); + } + + wl_display_disconnect(display); + + exit(0); +} + +static void +client_test_queue_dispatch_timeout(void) +{ + struct wl_display *display; + struct timespec timeout; + int ret = 0; + + display = wl_display_connect(NULL); + assert(display); + + timespec_from_msec(&timeout, 100); + + ret = wl_display_dispatch_timeout(display, &timeout); + assert(ret == 0); + + wl_display_disconnect(display); + + exit(0); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -709,3 +772,27 @@ TEST(queue_names) display_destroy(d); } + +TEST(queue_dispatch_simple) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_dispatch_simple); + display_run(d); + + display_destroy(d); +} + +TEST(queue_dispatch_timeout) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_dispatch_timeout); + display_run(d); + + display_destroy(d); +} From 02ad102e2d2d0dbb9529d00ab52ca4ff276d2ae3 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Wed, 29 Jan 2025 13:27:44 +0000 Subject: [PATCH 1043/1152] build: Add -lm to pkg-config dependencies Now that wl_fixed_from_double() calls round() from a function declared in a header, our users need to explicitly pick that dependency up in order to avoid build errors. Signed-off-by: Daniel Stone Closes: wayland/weston#991 --- src/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/meson.build b/src/meson.build index 5d04334e..984e34ab 100644 --- a/src/meson.build +++ b/src/meson.build @@ -212,6 +212,7 @@ if get_option('libraries') description: 'Server side implementation of the Wayland protocol', version: meson.project_version(), filebase: 'wayland-server', + libraries: mathlib_dep, variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()) @@ -251,6 +252,7 @@ if get_option('libraries') description: 'Wayland client side library', version: meson.project_version(), filebase: 'wayland-client', + libraries: mathlib_dep, variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()) From 7c2ffb0d712ca1aafbfa94c71f80226490bcbd28 Mon Sep 17 00:00:00 2001 From: David Redondo Date: Wed, 5 Feb 2025 09:21:43 +0100 Subject: [PATCH 1044/1152] Make wayland-util.h -Wundef safe when compiled by a C++ compiler Fixes #522 Signed-off-by: David Redondo --- src/wayland-util.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index 4edec8b0..c929a1ab 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -48,7 +48,7 @@ extern "C" { #endif /** Deprecated attribute */ -#if __STDC_VERSION__ >= 202311L +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L #define WL_DEPRECATED [[deprecated]] #elif defined(__GNUC__) && __GNUC__ >= 4 #define WL_DEPRECATED __attribute__ ((deprecated)) @@ -70,7 +70,7 @@ extern "C" { #define WL_PRINTF(x, y) #endif -#if __STDC_VERSION__ >= 202311L +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L #define WL_TYPEOF(expr) typeof(expr) #else #define WL_TYPEOF(expr) __typeof__(expr) From afd498b6f561b82b88bf1b647209c9ef0dca9e94 Mon Sep 17 00:00:00 2001 From: David Redondo Date: Wed, 5 Feb 2025 09:27:22 +0100 Subject: [PATCH 1045/1152] Also use [[deprecated]] when compiling with at least C++14 Signed-off-by: David Redondo --- src/wayland-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-util.h b/src/wayland-util.h index c929a1ab..4540f040 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -48,7 +48,7 @@ extern "C" { #endif /** Deprecated attribute */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || (defined(__cplusplus) && __cplusplus >= 201402L) #define WL_DEPRECATED [[deprecated]] #elif defined(__GNUC__) && __GNUC__ >= 4 #define WL_DEPRECATED __attribute__ ((deprecated)) From 1ab6b693b16e1d9734496fe60c8a6ed277e4dec3 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 5 Feb 2025 22:41:33 +0200 Subject: [PATCH 1046/1152] Forward declarate timespec struct The `timespec` struct is defined in `time.h` header but only if `_POSIX_C_SOURCE` is set or when using the C11 standard. Signed-off-by: Vlad Zahorodnii --- src/wayland-client-core.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 157da431..a70d4f09 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -27,7 +27,6 @@ #define WAYLAND_CLIENT_CORE_H #include -#include #include "wayland-util.h" #include "wayland-version.h" @@ -35,6 +34,8 @@ extern "C" { #endif +struct timespec; + /** \class wl_proxy * * \brief Represents a protocol object on the client side. From dbfa8d784eed0949f3dd50c19a58873b5deb32c6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 23 Feb 2025 23:38:15 +0100 Subject: [PATCH 1047/1152] scanner: use separate guards for validator functions Generated XXX_is_valid() functions for enums are guarded behind the same #define as the enum itself. This worked fine until recently, but since fbd7460737c9 ("scanner: add new enum-header mode") we're also generating enum-only headers. When including the enum-only header first, and then the server header, the validator functions are missing. Define a separate guard to fix this. Signed-off-by: Simon Ser --- src/scanner.c | 14 +++- tests/data/example-server.h | 144 +++++++++++++++++++++++++++------ tests/data/small-server-core.h | 12 ++- tests/data/small-server.h | 12 ++- 4 files changed, 151 insertions(+), 31 deletions(-) diff --git a/src/scanner.c b/src/scanner.c index 3cd05d13..1b71e60c 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1383,6 +1383,11 @@ emit_validator(struct interface *interface, struct enumeration *e) { struct entry *entry; + printf("#ifndef %s_%s_ENUM_IS_VALID\n", + interface->uppercase_name, e->uppercase_name); + printf("#define %s_%s_ENUM_IS_VALID\n", + interface->uppercase_name, e->uppercase_name); + printf("/**\n" " * @ingroup iface_%s\n" " * Validate a %s %s value.\n" @@ -1420,6 +1425,9 @@ emit_validator(struct interface *interface, struct enumeration *e) " }\n"); } printf("}\n"); + + printf("#endif /* %s_%s_ENUM_IS_VALID */\n\n", + interface->uppercase_name, e->uppercase_name); } static void @@ -1483,11 +1491,11 @@ emit_enumerations(struct interface *interface, bool with_validators) } - if (with_validators) - emit_validator(interface, e); - printf("#endif /* %s_%s_ENUM */\n\n", interface->uppercase_name, e->uppercase_name); + + if (with_validators) + emit_validator(interface, e); } } diff --git a/tests/data/example-server.h b/tests/data/example-server.h index 2fad7097..0ddc73db 100644 --- a/tests/data/example-server.h +++ b/tests/data/example-server.h @@ -901,6 +901,10 @@ enum wl_display_error { */ WL_DISPLAY_ERROR_NO_MEMORY = 2, }; +#endif /* WL_DISPLAY_ERROR_ENUM */ + +#ifndef WL_DISPLAY_ERROR_ENUM_IS_VALID +#define WL_DISPLAY_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_display * Validate a wl_display error value. @@ -921,7 +925,7 @@ wl_display_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_DISPLAY_ERROR_ENUM */ +#endif /* WL_DISPLAY_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_display @@ -1194,6 +1198,10 @@ enum wl_shm_error { */ WL_SHM_ERROR_INVALID_FD = 2, }; +#endif /* WL_SHM_ERROR_ENUM */ + +#ifndef WL_SHM_ERROR_ENUM_IS_VALID +#define WL_SHM_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_shm * Validate a wl_shm error value. @@ -1214,7 +1222,7 @@ wl_shm_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SHM_ERROR_ENUM */ +#endif /* WL_SHM_ERROR_ENUM_IS_VALID */ #ifndef WL_SHM_FORMAT_ENUM #define WL_SHM_FORMAT_ENUM @@ -1466,6 +1474,10 @@ enum wl_shm_format { */ WL_SHM_FORMAT_YVU444 = 0x34325659, }; +#endif /* WL_SHM_FORMAT_ENUM */ + +#ifndef WL_SHM_FORMAT_ENUM_IS_VALID +#define WL_SHM_FORMAT_ENUM_IS_VALID /** * @ingroup iface_wl_shm * Validate a wl_shm format value. @@ -1596,7 +1608,7 @@ wl_shm_format_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SHM_FORMAT_ENUM */ +#endif /* WL_SHM_FORMAT_ENUM_IS_VALID */ /** * @ingroup iface_wl_shm @@ -1706,6 +1718,10 @@ enum wl_data_offer_error { */ WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, }; +#endif /* WL_DATA_OFFER_ERROR_ENUM */ + +#ifndef WL_DATA_OFFER_ERROR_ENUM_IS_VALID +#define WL_DATA_OFFER_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_data_offer * Validate a wl_data_offer error value. @@ -1728,7 +1744,7 @@ wl_data_offer_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_DATA_OFFER_ERROR_ENUM */ +#endif /* WL_DATA_OFFER_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_data_offer @@ -1940,6 +1956,10 @@ enum wl_data_source_error { */ WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, }; +#endif /* WL_DATA_SOURCE_ERROR_ENUM */ + +#ifndef WL_DATA_SOURCE_ERROR_ENUM_IS_VALID +#define WL_DATA_SOURCE_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_data_source * Validate a wl_data_source error value. @@ -1958,7 +1978,7 @@ wl_data_source_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_DATA_SOURCE_ERROR_ENUM */ +#endif /* WL_DATA_SOURCE_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_data_source @@ -2130,6 +2150,10 @@ enum wl_data_device_error { */ WL_DATA_DEVICE_ERROR_ROLE = 0, }; +#endif /* WL_DATA_DEVICE_ERROR_ENUM */ + +#ifndef WL_DATA_DEVICE_ERROR_ENUM_IS_VALID +#define WL_DATA_DEVICE_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_data_device * Validate a wl_data_device error value. @@ -2146,7 +2170,7 @@ wl_data_device_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_DATA_DEVICE_ERROR_ENUM */ +#endif /* WL_DATA_DEVICE_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_data_device @@ -2387,6 +2411,10 @@ enum wl_data_device_manager_dnd_action { */ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, }; +#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ + +#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID +#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID /** * @ingroup iface_wl_data_device_manager * Validate a wl_data_device_manager dnd_action value. @@ -2407,7 +2435,7 @@ wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) { valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; return (value & ~valid) == 0; } -#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ +#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID */ /** * @ingroup iface_wl_data_device_manager @@ -2454,6 +2482,10 @@ enum wl_shell_error { */ WL_SHELL_ERROR_ROLE = 0, }; +#endif /* WL_SHELL_ERROR_ENUM */ + +#ifndef WL_SHELL_ERROR_ENUM_IS_VALID +#define WL_SHELL_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_shell * Validate a wl_shell error value. @@ -2470,7 +2502,7 @@ wl_shell_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SHELL_ERROR_ENUM */ +#endif /* WL_SHELL_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_shell @@ -2549,6 +2581,10 @@ enum wl_shell_surface_resize { */ WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, }; +#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ + +#ifndef WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID +#define WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID /** * @ingroup iface_wl_shell_surface * Validate a wl_shell_surface resize value. @@ -2579,7 +2615,7 @@ wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) { valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; return (value & ~valid) == 0; } -#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ +#endif /* WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID */ #ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM #define WL_SHELL_SURFACE_TRANSIENT_ENUM @@ -2596,6 +2632,10 @@ enum wl_shell_surface_transient { */ WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, }; +#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ + +#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID +#define WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID /** * @ingroup iface_wl_shell_surface * Validate a wl_shell_surface transient value. @@ -2610,7 +2650,7 @@ wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) { valid |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE; return (value & ~valid) == 0; } -#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ +#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID */ #ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM #define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM @@ -2640,6 +2680,10 @@ enum wl_shell_surface_fullscreen_method { */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, }; +#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ + +#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID +#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID /** * @ingroup iface_wl_shell_surface * Validate a wl_shell_surface fullscreen_method value. @@ -2662,7 +2706,7 @@ wl_shell_surface_fullscreen_method_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ +#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID */ /** * @ingroup iface_wl_shell_surface @@ -2994,6 +3038,10 @@ enum wl_surface_error { */ WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, }; +#endif /* WL_SURFACE_ERROR_ENUM */ + +#ifndef WL_SURFACE_ERROR_ENUM_IS_VALID +#define WL_SURFACE_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_surface * Validate a wl_surface error value. @@ -3012,7 +3060,7 @@ wl_surface_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SURFACE_ERROR_ENUM */ +#endif /* WL_SURFACE_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_surface @@ -3471,6 +3519,10 @@ enum wl_seat_capability { */ WL_SEAT_CAPABILITY_TOUCH = 4, }; +#endif /* WL_SEAT_CAPABILITY_ENUM */ + +#ifndef WL_SEAT_CAPABILITY_ENUM_IS_VALID +#define WL_SEAT_CAPABILITY_ENUM_IS_VALID /** * @ingroup iface_wl_seat * Validate a wl_seat capability value. @@ -3489,7 +3541,7 @@ wl_seat_capability_is_valid(uint32_t value, uint32_t version) { valid |= WL_SEAT_CAPABILITY_TOUCH; return (value & ~valid) == 0; } -#endif /* WL_SEAT_CAPABILITY_ENUM */ +#endif /* WL_SEAT_CAPABILITY_ENUM_IS_VALID */ /** * @ingroup iface_wl_seat @@ -3613,6 +3665,10 @@ enum wl_pointer_error { */ WL_POINTER_ERROR_ROLE = 0, }; +#endif /* WL_POINTER_ERROR_ENUM */ + +#ifndef WL_POINTER_ERROR_ENUM_IS_VALID +#define WL_POINTER_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_pointer * Validate a wl_pointer error value. @@ -3629,7 +3685,7 @@ wl_pointer_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_POINTER_ERROR_ENUM */ +#endif /* WL_POINTER_ERROR_ENUM_IS_VALID */ #ifndef WL_POINTER_BUTTON_STATE_ENUM #define WL_POINTER_BUTTON_STATE_ENUM @@ -3650,6 +3706,10 @@ enum wl_pointer_button_state { */ WL_POINTER_BUTTON_STATE_PRESSED = 1, }; +#endif /* WL_POINTER_BUTTON_STATE_ENUM */ + +#ifndef WL_POINTER_BUTTON_STATE_ENUM_IS_VALID +#define WL_POINTER_BUTTON_STATE_ENUM_IS_VALID /** * @ingroup iface_wl_pointer * Validate a wl_pointer button_state value. @@ -3668,7 +3728,7 @@ wl_pointer_button_state_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_POINTER_BUTTON_STATE_ENUM */ +#endif /* WL_POINTER_BUTTON_STATE_ENUM_IS_VALID */ #ifndef WL_POINTER_AXIS_ENUM #define WL_POINTER_AXIS_ENUM @@ -3688,6 +3748,10 @@ enum wl_pointer_axis { */ WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, }; +#endif /* WL_POINTER_AXIS_ENUM */ + +#ifndef WL_POINTER_AXIS_ENUM_IS_VALID +#define WL_POINTER_AXIS_ENUM_IS_VALID /** * @ingroup iface_wl_pointer * Validate a wl_pointer axis value. @@ -3706,7 +3770,7 @@ wl_pointer_axis_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_POINTER_AXIS_ENUM */ +#endif /* WL_POINTER_AXIS_ENUM_IS_VALID */ #ifndef WL_POINTER_AXIS_SOURCE_ENUM #define WL_POINTER_AXIS_SOURCE_ENUM @@ -3754,6 +3818,10 @@ enum wl_pointer_axis_source { * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 +#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ + +#ifndef WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID +#define WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID /** * @ingroup iface_wl_pointer * Validate a wl_pointer axis_source value. @@ -3776,7 +3844,7 @@ wl_pointer_axis_source_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ +#endif /* WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID */ /** * @ingroup iface_wl_pointer @@ -4037,6 +4105,10 @@ enum wl_keyboard_keymap_format { */ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, }; +#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ + +#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID +#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID /** * @ingroup iface_wl_keyboard * Validate a wl_keyboard keymap_format value. @@ -4055,7 +4127,7 @@ wl_keyboard_keymap_format_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ +#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID */ #ifndef WL_KEYBOARD_KEY_STATE_ENUM #define WL_KEYBOARD_KEY_STATE_ENUM @@ -4075,6 +4147,10 @@ enum wl_keyboard_key_state { */ WL_KEYBOARD_KEY_STATE_PRESSED = 1, }; +#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ + +#ifndef WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID +#define WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID /** * @ingroup iface_wl_keyboard * Validate a wl_keyboard key_state value. @@ -4093,7 +4169,7 @@ wl_keyboard_key_state_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ +#endif /* WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID */ /** * @ingroup iface_wl_keyboard @@ -4419,6 +4495,10 @@ enum wl_output_subpixel { */ WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, }; +#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ + +#ifndef WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID +#define WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID /** * @ingroup iface_wl_output * Validate a wl_output subpixel value. @@ -4445,7 +4525,7 @@ wl_output_subpixel_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ +#endif /* WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID */ #ifndef WL_OUTPUT_TRANSFORM_ENUM #define WL_OUTPUT_TRANSFORM_ENUM @@ -4499,6 +4579,10 @@ enum wl_output_transform { */ WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, }; +#endif /* WL_OUTPUT_TRANSFORM_ENUM */ + +#ifndef WL_OUTPUT_TRANSFORM_ENUM_IS_VALID +#define WL_OUTPUT_TRANSFORM_ENUM_IS_VALID /** * @ingroup iface_wl_output * Validate a wl_output transform value. @@ -4529,7 +4613,7 @@ wl_output_transform_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_OUTPUT_TRANSFORM_ENUM */ +#endif /* WL_OUTPUT_TRANSFORM_ENUM_IS_VALID */ #ifndef WL_OUTPUT_MODE_ENUM #define WL_OUTPUT_MODE_ENUM @@ -4550,6 +4634,10 @@ enum wl_output_mode { */ WL_OUTPUT_MODE_PREFERRED = 0x2, }; +#endif /* WL_OUTPUT_MODE_ENUM */ + +#ifndef WL_OUTPUT_MODE_ENUM_IS_VALID +#define WL_OUTPUT_MODE_ENUM_IS_VALID /** * @ingroup iface_wl_output * Validate a wl_output mode value. @@ -4566,7 +4654,7 @@ wl_output_mode_is_valid(uint32_t value, uint32_t version) { valid |= WL_OUTPUT_MODE_PREFERRED; return (value & ~valid) == 0; } -#endif /* WL_OUTPUT_MODE_ENUM */ +#endif /* WL_OUTPUT_MODE_ENUM_IS_VALID */ /** * @ingroup iface_wl_output @@ -4734,6 +4822,10 @@ enum wl_subcompositor_error { */ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, }; +#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ + +#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID +#define WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_subcompositor * Validate a wl_subcompositor error value. @@ -4750,7 +4842,7 @@ wl_subcompositor_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ +#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_subcompositor @@ -4805,6 +4897,10 @@ enum wl_subsurface_error { */ WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, }; +#endif /* WL_SUBSURFACE_ERROR_ENUM */ + +#ifndef WL_SUBSURFACE_ERROR_ENUM_IS_VALID +#define WL_SUBSURFACE_ERROR_ENUM_IS_VALID /** * @ingroup iface_wl_subsurface * Validate a wl_subsurface error value. @@ -4821,7 +4917,7 @@ wl_subsurface_error_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* WL_SUBSURFACE_ERROR_ENUM */ +#endif /* WL_SUBSURFACE_ERROR_ENUM_IS_VALID */ /** * @ingroup iface_wl_subsurface diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h index d4476959..4248d455 100644 --- a/tests/data/small-server-core.h +++ b/tests/data/small-server-core.h @@ -107,6 +107,10 @@ enum intf_A_foo { * @ingroup iface_intf_A */ #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 +#endif /* INTF_A_FOO_ENUM */ + +#ifndef INTF_A_FOO_ENUM_IS_VALID +#define INTF_A_FOO_ENUM_IS_VALID /** * @ingroup iface_intf_A * Validate a intf_A foo value. @@ -131,7 +135,7 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* INTF_A_FOO_ENUM */ +#endif /* INTF_A_FOO_ENUM_IS_VALID */ #ifndef INTF_A_BAR_ENUM #define INTF_A_BAR_ENUM @@ -154,6 +158,10 @@ enum intf_A_bar { * @ingroup iface_intf_A */ #define INTF_A_BAR_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_BAR_ENUM */ + +#ifndef INTF_A_BAR_ENUM_IS_VALID +#define INTF_A_BAR_ENUM_IS_VALID /** * @ingroup iface_intf_A * Validate a intf_A bar value. @@ -172,7 +180,7 @@ intf_A_bar_is_valid(uint32_t value, uint32_t version) { valid |= INTF_A_BAR_THIRD; return (value & ~valid) == 0; } -#endif /* INTF_A_BAR_ENUM */ +#endif /* INTF_A_BAR_ENUM_IS_VALID */ /** * @ingroup iface_intf_A diff --git a/tests/data/small-server.h b/tests/data/small-server.h index 9cafcd93..743fc8d7 100644 --- a/tests/data/small-server.h +++ b/tests/data/small-server.h @@ -107,6 +107,10 @@ enum intf_A_foo { * @ingroup iface_intf_A */ #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 +#endif /* INTF_A_FOO_ENUM */ + +#ifndef INTF_A_FOO_ENUM_IS_VALID +#define INTF_A_FOO_ENUM_IS_VALID /** * @ingroup iface_intf_A * Validate a intf_A foo value. @@ -131,7 +135,7 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) { return false; } } -#endif /* INTF_A_FOO_ENUM */ +#endif /* INTF_A_FOO_ENUM_IS_VALID */ #ifndef INTF_A_BAR_ENUM #define INTF_A_BAR_ENUM @@ -154,6 +158,10 @@ enum intf_A_bar { * @ingroup iface_intf_A */ #define INTF_A_BAR_THIRD_SINCE_VERSION 2 +#endif /* INTF_A_BAR_ENUM */ + +#ifndef INTF_A_BAR_ENUM_IS_VALID +#define INTF_A_BAR_ENUM_IS_VALID /** * @ingroup iface_intf_A * Validate a intf_A bar value. @@ -172,7 +180,7 @@ intf_A_bar_is_valid(uint32_t value, uint32_t version) { valid |= INTF_A_BAR_THIRD; return (value & ~valid) == 0; } -#endif /* INTF_A_BAR_ENUM */ +#endif /* INTF_A_BAR_ENUM_IS_VALID */ /** * @ingroup iface_intf_A From 7033e74857a01cd8fc07cd2e6336d8bfe43cbed5 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 12 Mar 2025 21:13:40 +0100 Subject: [PATCH 1048/1152] client: document get_listener behavior for dispatchers This seems to have been the case since 2013. This is useful for wrappers that need two pointers to identify proxies. One pointer (stored in the user data) pointing to a singleton object to identify that the proxy has a known structure. And one pointer (stored in the dispatcher data) pointing to per-proxy data. Signed-off-by: Julian Orth --- src/wayland-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index 8df160b4..3d0ef7b4 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -674,6 +674,9 @@ wl_proxy_add_listener(struct wl_proxy *proxy, * This function is useful in clients with multiple listeners on the same * interface to allow the identification of which code to execute. * + * If \ref wl_proxy_add_dispatcher was used, this function returns the + * dispatcher_data pointer instead. + * * \memberof wl_proxy */ WL_EXPORT const void * From 6137c8c21383d7ebb92cf3331be56ca0aecccd5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 21 Jan 2025 15:27:22 +0100 Subject: [PATCH 1049/1152] protocol: Clarify wl_buffer.release description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sebastian pointed out that the existing text could be read as wl_buffer.destroy not being allowed before the wl_buffer.release event arrives, contrary to what the wl_surface.attach description says. Clarify to be consistent with the latter. This is a follow-up for https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/141 . Signed-off-by: Michel Dänzer v2: * Simplify clarification, don't talk about callbacks. (Julian Orth) * Add reference to details in the description of wl_surface.attach. (Daniel Stone) v3: * Tweak clarification again. (Sebastian Wick) v4: * Make clarification even less ambiguous. (Simon Ser, Julian Orth) v5: * Just refer to the description of wl_surface.attach instead of trying to clarify anything here. (Sebastian Wick) --- protocol/wayland.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index f32918e9..1af51d36 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -501,8 +501,10 @@ Sent when this wl_buffer is no longer used by the compositor. - The client is now free to reuse or destroy this buffer and its - backing storage. + + For more information on when release events may or may not be sent, + and what consequences it has, please see the description of + wl_surface.attach. If a client receives a release event before the frame callback requested in the same wl_surface.commit that attaches this From 9ec01ab2dc08c1c60ec4fcf7df8defa652c52ae8 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 20 May 2025 21:30:56 +0200 Subject: [PATCH 1050/1152] shm: Linkify wl_shm_pool_unref in the ref_pool documentation Signed-off-by: Sebastian Wick --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 9b3aac61..d22353c6 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -503,7 +503,7 @@ wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer) * Returns a pointer to a buffer's shm_pool and increases the * shm_pool refcount. * - * The compositor must remember to call wl_shm_pool_unref when + * The compositor must remember to call wl_shm_pool_unref() when * it no longer needs the reference to ensure proper destruction * of the pool. * From af453f876e44f4cb990acc92b50d130e6efed667 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 20 May 2025 21:39:45 +0200 Subject: [PATCH 1051/1152] shm: Remove refcount check which cannot be triggered If the pool refcount reaches zero, it is freed, so accessing its members is UB which ASan would catch. Also simplify check for negative refcounts. Signed-off-by: Sebastian Wick --- src/wayland-shm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index d22353c6..27db8c65 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -143,17 +143,16 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external) { if (external) { pool->external_refcount--; - if (!(pool->external_refcount >= 0)) + if (pool->external_refcount < 0) wl_abort("Requested to unref an external reference to " "pool but none found\n"); if (pool->external_refcount == 0) shm_pool_finish_resize(pool); } else { pool->internal_refcount--; - if (!(pool->internal_refcount >= 0)) + if (pool->internal_refcount < 0) wl_abort("Requested to unref an internal reference to " "pool but none found\n"); - } if (pool->internal_refcount + pool->external_refcount > 0) @@ -513,10 +512,6 @@ wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer) WL_EXPORT struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) { - if (!(buffer->pool->internal_refcount + - buffer->pool->external_refcount)) - wl_abort("Can't get reference to pool that has been freed\n"); - buffer->pool->external_refcount++; return buffer->pool; } From 9367c4da76c9fd118d505e40ad5d554e8fe249a1 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Fri, 21 Mar 2025 19:42:52 +0100 Subject: [PATCH 1052/1152] shm: Add wl_shm_buffer ref and unref functions Shared memory buffers are currently tied to the lifetime of their underlying wl_buffer resource. This becomes problematic when the client destroys the resource after committing new state which references the wl_buffer because a compositor might have to defer applying the commit. This commit adds methods to keep the wl_shm_buffer alive longer than the underlying resource. This implicitly also keeps the buffer pool alive and because the wl_shm_buffer uses offsets into the pool, it even works when the underlying storage gets remapped somewhere else, which can happen when the client resizes the pool. Signed-off-by: Sebastian Wick --- src/wayland-server-core.h | 6 +++ src/wayland-shm.c | 78 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 15c3b762..005a3249 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -666,6 +666,12 @@ wl_shm_buffer_get_width(const struct wl_shm_buffer *buffer); int32_t wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer); +struct wl_shm_buffer * +wl_shm_buffer_ref(struct wl_shm_buffer *buffer); + +void +wl_shm_buffer_unref(struct wl_shm_buffer *buffer); + struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer); diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 27db8c65..bb622b60 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -84,6 +84,8 @@ struct wl_shm_pool { */ struct wl_shm_buffer { struct wl_resource *resource; + int internal_refcount; + int external_refcount; int32_t width, height; int32_t stride; uint32_t format; @@ -165,13 +167,36 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external) free(pool); } +static void +shm_buffer_unref(struct wl_shm_buffer *buffer, bool external) +{ + if (external) { + buffer->external_refcount--; + if (buffer->external_refcount < 0) { + wl_abort("Requested to unref an external reference to " + "buffer but none found\n"); + } + } else { + buffer->internal_refcount--; + if (buffer->internal_refcount < 0) { + wl_abort("Requested to unref an internal reference to " + "buffer but none found\n"); + } + } + + if (buffer->internal_refcount + buffer->external_refcount > 0) + return; + + shm_pool_unref(buffer->pool, false); + free(buffer); +} + static void destroy_buffer(struct wl_resource *resource) { struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource); - shm_pool_unref(buffer->pool, false); - free(buffer); + shm_buffer_unref(buffer, false); } static void @@ -237,6 +262,8 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, return; } + buffer->internal_refcount = 1; + buffer->external_refcount = 0; buffer->width = width; buffer->height = height; buffer->format = format; @@ -495,6 +522,45 @@ wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer) return buffer->height; } +/** Reference a shm_buffer + * + * \param buffer The buffer object + * + * Returns a pointer to the buffer and increases the refcount. + * + * The compositor must remember to call wl_shm_buffer_unref() when + * it no longer needs the reference to ensure proper destruction + * of the buffer. + * + * \memberof wl_shm_buffer + * \sa wl_shm_buffer_unref + */ +WL_EXPORT struct wl_shm_buffer * +wl_shm_buffer_ref(struct wl_shm_buffer *buffer) +{ + buffer->external_refcount++; + return buffer; +} + +/** Unreference a shm_buffer + * + * \param buffer The buffer object + * + * Drops a reference to a buffer object. + * + * This is only necessary if the compositor has explicitly + * taken a reference with wl_shm_buffer_ref(), otherwise + * the buffer will be automatically destroyed when appropriate. + * + * \memberof wl_shm_buffer + * \sa wl_shm_buffer_ref + */ +WL_EXPORT void +wl_shm_buffer_unref(struct wl_shm_buffer *buffer) +{ + shm_buffer_unref(buffer, true); +} + /** Get a reference to a shm_buffer's shm_pool * * \param buffer The buffer object @@ -693,9 +759,11 @@ wl_shm_buffer_end_access(struct wl_shm_buffer *buffer) if (--sigbus_data->access_count == 0) { if (sigbus_data->fallback_mapping_used) { - wl_resource_post_error(buffer->resource, - WL_SHM_ERROR_INVALID_FD, - "error accessing SHM buffer"); + if (buffer->resource) { + wl_resource_post_error(buffer->resource, + WL_SHM_ERROR_INVALID_FD, + "error accessing SHM buffer"); + } sigbus_data->fallback_mapping_used = 0; } From d2a3d33063ea0266eee55a54c8bb1d65a7acaca9 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Fri, 21 Mar 2025 19:43:23 +0100 Subject: [PATCH 1053/1152] shm: Generate an error when shm access failed even without a resource Signed-off-by: Sebastian Wick --- src/wayland-shm.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index bb622b60..b8c73731 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -86,6 +86,8 @@ struct wl_shm_buffer { struct wl_resource *resource; int internal_refcount; int external_refcount; + struct wl_client *client; + struct wl_listener client_destroy_listener; int32_t width, height; int32_t stride; uint32_t format; @@ -187,6 +189,8 @@ shm_buffer_unref(struct wl_shm_buffer *buffer, bool external) if (buffer->internal_refcount + buffer->external_refcount > 0) return; + if (buffer->client) + wl_list_remove(&buffer->client_destroy_listener.link); shm_pool_unref(buffer->pool, false); free(buffer); } @@ -230,6 +234,17 @@ format_is_supported(struct wl_client *client, uint32_t format) return false; } + +static void +shm_buffer_client_destroy_notify(struct wl_listener *listener, void *data) +{ + struct wl_shm_buffer *buffer = + wl_container_of(listener, buffer, client_destroy_listener); + + buffer->client = NULL; + wl_list_remove(&buffer->client_destroy_listener.link); +} + static void shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, uint32_t id, int32_t offset, @@ -262,6 +277,12 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, return; } + buffer->client = client; + buffer->client_destroy_listener.notify = + shm_buffer_client_destroy_notify; + wl_client_add_destroy_listener(buffer->client, + &buffer->client_destroy_listener); + buffer->internal_refcount = 1; buffer->external_refcount = 0; buffer->width = width; @@ -763,6 +784,11 @@ wl_shm_buffer_end_access(struct wl_shm_buffer *buffer) wl_resource_post_error(buffer->resource, WL_SHM_ERROR_INVALID_FD, "error accessing SHM buffer"); + } else if (buffer->client) { + wl_client_post_implementation_error(buffer->client, + "Error accessing SHM buffer of a " + "wl_buffer resource which has " + "already been destroyed"); } sigbus_data->fallback_mapping_used = 0; } From 9dd1b2d7e3eb89b5161431c99a6aca8f284621ae Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 15 Mar 2025 23:49:43 +0100 Subject: [PATCH 1054/1152] shm: fix comment about wl_shm_buffer_begin_access() safety The paragraph later says that accessing different buffers is allowed. The function checks whether the same pool is accessed. Signed-off-by: Simon Ser --- src/wayland-shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index b8c73731..b87a5b8b 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -717,7 +717,7 @@ init_sigbus_data_key(void) * terminate. * * It is safe to nest calls to these functions as long as the nested - * calls are all accessing the same buffer. The number of calls to + * calls are all accessing the same pool. The number of calls to * wl_shm_buffer_end_access must match the number of calls to * wl_shm_buffer_begin_access. These functions are thread-safe and it * is allowed to simultaneously access different buffers or the same From 66fc3f007dca7b3e526e86475d3ec74d30d363b8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 15 Mar 2025 23:52:50 +0100 Subject: [PATCH 1055/1152] shm: linkify function references in docs Parentheses make it so the generated HTML documentation contains links, which makes navigation easier. Signed-off-by: Simon Ser --- src/wayland-shm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/wayland-shm.c b/src/wayland-shm.c index b87a5b8b..3ac4add2 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -509,8 +509,8 @@ wl_shm_buffer_get_stride(const struct wl_shm_buffer *buffer) * SIGBUS signals. This can happen if the client claims that the * buffer is larger than it is or if something truncates the * underlying file. To prevent this signal from causing the compositor - * to crash you should call wl_shm_buffer_begin_access and - * wl_shm_buffer_end_access around code that reads from the memory. + * to crash you should call wl_shm_buffer_begin_access() and + * wl_shm_buffer_end_access() around code that reads from the memory. * * \memberof wl_shm_buffer */ @@ -700,7 +700,7 @@ init_sigbus_data_key(void) * In order to make the compositor robust against clients that change * the size of the underlying file or lie about its size, you should * protect access to the buffer by calling this function before - * reading from the memory and call wl_shm_buffer_end_access + * reading from the memory and call wl_shm_buffer_end_access() * afterwards. This will install a signal handler for SIGBUS which * will prevent the compositor from crashing. * @@ -711,15 +711,15 @@ init_sigbus_data_key(void) * * If a SIGBUS signal is received for an address within the range of * the SHM pool of the given buffer then the client will be sent an - * error event when wl_shm_buffer_end_access is called. If the signal + * error event when wl_shm_buffer_end_access() is called. If the signal * is for an address outside that range then the signal handler will * reraise the signal which would will likely cause the compositor to * terminate. * * It is safe to nest calls to these functions as long as the nested * calls are all accessing the same pool. The number of calls to - * wl_shm_buffer_end_access must match the number of calls to - * wl_shm_buffer_begin_access. These functions are thread-safe and it + * wl_shm_buffer_end_access() must match the number of calls to + * wl_shm_buffer_begin_access(). These functions are thread-safe and it * is allowed to simultaneously access different buffers or the same * buffer from multiple threads. * @@ -753,11 +753,11 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer) sigbus_data->access_count++; } -/** Ends the access to a buffer started by wl_shm_buffer_begin_access +/** Ends the access to a buffer started by wl_shm_buffer_begin_access() * * \param buffer The SHM buffer * - * This should be called after wl_shm_buffer_begin_access once the + * This should be called after wl_shm_buffer_begin_access() once the * buffer is no longer being accessed. If a SIGBUS signal was * generated in-between these two calls then the resource for the * given buffer will be sent an error. From 3214f858e2bc226c16c280d832a836eae8a671c4 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 26 Sep 2024 12:15:37 +0100 Subject: [PATCH 1056/1152] protocol: Clarify sending of wl_seat.capabilities It wasn't explicitly stated that wl_seat.capabilities should also be sent on bind. Everyone did because it was obviously sensible. This also clarifies that static seat name should be sent before announcing capabilities so clients can associate these devices with the right seat name. Signed-off-by: David Edmundson --- protocol/wayland.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 1af51d36..a87d07fe 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1913,9 +1913,10 @@ - This is emitted whenever a seat gains or loses the pointer, - keyboard or touch capabilities. The argument is a capability - enum containing the complete set of capabilities this seat has. + This is sent on binding to the seat global or whenever a seat gains + or loses the pointer, keyboard or touch capabilities. + The argument is a capability enum containing the complete set of + capabilities this seat has. When the pointer capability is added, a client may create a wl_pointer object using the wl_seat.get_pointer request. This object @@ -1997,9 +1998,9 @@ The same seat names are used for all clients. Thus, the name can be shared across processes to refer to a specific wl_seat global. - The name event is sent after binding to the seat global. This event is - only sent once per seat object, and the name does not change over the - lifetime of the wl_seat global. + The name event is sent after binding to the seat global, and should be sent + before announcing capabilities. This event only sent once per seat object, + and the name does not change over the lifetime of the wl_seat global. Compositors may re-use the same seat name if the wl_seat global is destroyed and re-created later. From 44972321025e6b34cd5544c2053559c64f1b29af Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 6 May 2025 23:45:17 +0200 Subject: [PATCH 1057/1152] client: add wl_proxy_get_interface() This is useful for the wayland bindings/scanner I'm working on for a dynamically typed language. Signed-off-by: Isaac Freund --- src/wayland-client-core.h | 3 +++ src/wayland-client.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index a70d4f09..970e6254 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -221,6 +221,9 @@ wl_proxy_get_tag(struct wl_proxy *proxy); const char * wl_proxy_get_class(struct wl_proxy *proxy); +const struct wl_interface * +wl_proxy_get_interface(struct wl_proxy *proxy); + struct wl_display * wl_proxy_get_display(struct wl_proxy *proxy); diff --git a/src/wayland-client.c b/src/wayland-client.c index 3d0ef7b4..25aa1cd4 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -2513,6 +2513,20 @@ wl_proxy_get_class(struct wl_proxy *proxy) return proxy->object.interface->name; } +/** Get the interface of a proxy object + * + * \param proxy The proxy object + * \return The interface of the object associated with the proxy + * + * \memberof wl_proxy + * \since 1.24 + */ +WL_EXPORT const struct wl_interface * +wl_proxy_get_interface(struct wl_proxy *proxy) +{ + return proxy->object.interface; +} + /** Get the display of a proxy object * * \param proxy The proxy object From 8cad6f7b826546e4faa2d366aed898b5651f73b4 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 6 May 2025 23:48:57 +0200 Subject: [PATCH 1058/1152] server: add wl_resource_get_interface() This is useful for the wayland bindings/scanner I'm working on for a dynamically typed language. Signed-off-by: Isaac Freund --- src/wayland-server-core.h | 3 +++ src/wayland-server.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 005a3249..c2dcc218 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -621,6 +621,9 @@ wl_resource_instance_of(struct wl_resource *resource, const char * wl_resource_get_class(const struct wl_resource *resource); +const struct wl_interface * +wl_resource_get_interface(struct wl_resource *resource); + void wl_resource_add_destroy_listener(struct wl_resource *resource, struct wl_listener *listener); diff --git a/src/wayland-server.c b/src/wayland-server.c index e5805669..fb99eb23 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -905,6 +905,20 @@ wl_resource_get_class(const struct wl_resource *resource) return resource->object.interface->name; } +/** Get the interface of a resource object + * + * \param resource The resource object + * \return The interface of the object associated with the resource + * + * \memberof wl_resource + * \since 1.24 + */ +WL_EXPORT const struct wl_interface * +wl_resource_get_interface(struct wl_resource *resource) +{ + return resource->object.interface; +} + /** * Add a listener to be called at the beginning of wl_client destruction * From cc06c3825f38ab069ff787311c9ec9f172579347 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Thu, 12 Sep 2024 15:26:26 +0200 Subject: [PATCH 1059/1152] Fix typos Typos found with codespell and during code audit. Signed-off-by: Tobias Stoeckmann --- cursor/xcursor.c | 6 +++--- doc/publican/sources/Introduction.xml | 2 +- src/wayland-server.c | 2 +- tests/connection-test.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 0d5761f2..2b6c47d5 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -798,14 +798,14 @@ xcursor_load_theme_protected(const char *theme, int size, free(xcursor_path); } -/** Load all the cursor of a theme +/** Load all the cursors of a theme * * This function loads all the cursor images of a given theme and its - * inherited themes. Each cursor is loaded into an struct xcursor_images object + * inherited themes. Each cursor is loaded into a struct xcursor_images object * which is passed to the caller's load callback. If a cursor appears * more than once across all the inherited themes, the load callback * will be called multiple times, with possibly different struct xcursor_images - * object which have the same name. The user is expected to destroy the + * objects which have the same name. The user is expected to destroy the * struct xcursor_images objects passed to the callback with * xcursor_images_destroy(). * diff --git a/doc/publican/sources/Introduction.xml b/doc/publican/sources/Introduction.xml index 276db2da..f2a82744 100644 --- a/doc/publican/sources/Introduction.xml +++ b/doc/publican/sources/Introduction.xml @@ -87,7 +87,7 @@ Overall, the philosophy of Wayland is to provide clients with a way to - manage windows and how their contents is displayed. Rendering is left + manage windows and how their contents are displayed. Rendering is left to clients, and system wide memory management interfaces are used to pass buffer handles between clients and the compositing manager. diff --git a/src/wayland-server.c b/src/wayland-server.c index fb99eb23..a538519e 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -2074,7 +2074,7 @@ wl_log_set_handler_server(wl_log_func_t handler) * \param func The function to call to log a new protocol message * \param user_data The user data pointer to pass to \a func * - * \return The protol logger object on success, NULL on failure. + * \return The protocol logger object on success, NULL on failure. * * \sa wl_protocol_logger_destroy * diff --git a/tests/connection-test.c b/tests/connection-test.c index dde5d89c..aed97a0a 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -686,7 +686,7 @@ TEST(connection_marshal_big_enough) TEST(connection_marshal_unbounded_boundary_size) { - /* A string of lenth 8178 requires a buffer size of exactly 2^13. */ + /* A string of length 8178 requires a buffer size of exactly 2^13. */ struct marshal_data data; char *big_string = malloc(8178); assert(big_string); From 9b169ff945a8fdddc3a92b1990bddc29a7d24465 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 16 Mar 2025 00:13:17 +0100 Subject: [PATCH 1060/1152] protocol: drop reference to linux-explicit-synchronization This protocol has been superseded. Replace this outdated reference with a generic hint that protocol extensions may provide this functionality. Signed-off-by: Simon Ser --- protocol/wayland.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index a87d07fe..bee74a10 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1506,7 +1506,8 @@ the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this case. Alternatively, a client could create multiple wl_buffer objects - from the same backing storage or use wp_linux_buffer_release. + from the same backing storage or use a protocol extension providing + per-commit release notifications. Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release From 62cd0990e843095dc91811e2668131783df8f055 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 22 May 2025 21:00:30 +0200 Subject: [PATCH 1061/1152] build: bump version to 1.23.90 for the RC1 release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6b05bb52..a3126b63 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.23.90', + version: '1.23.91', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From 827d0c30adc4519fafa7a9c725ff355b1d4fa3bd Mon Sep 17 00:00:00 2001 From: Caitlyn Stewart Date: Tue, 27 May 2025 13:09:24 +0100 Subject: [PATCH 1062/1152] connection: fix segfault in wl_closure_invoke() Signed-off-by: Caitlyn Stewart --- src/connection.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/connection.c b/src/connection.c index 34495211..3ef8688d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1229,6 +1229,11 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags, count + 2, &ffi_type_void, ffi_types); implementation = target->implementation; + if (!implementation) { + wl_abort("Implementation of resource %d of %s is NULL\n", + target->id, target->interface->name); + } + if (!implementation[opcode]) { wl_abort("listener function for opcode %u of %s is NULL\n", opcode, target->interface->name); From ecff0ee10c335f8f71251e67d615f4f719b6cbe1 Mon Sep 17 00:00:00 2001 From: Caitlyn Date: Tue, 27 May 2025 22:40:14 +0100 Subject: [PATCH 1063/1152] debug: Colorize output for easier reading Signed-off-by: Caitlyn --- src/connection.c | 29 ++++++++++++++++++++--------- src/wayland-client.c | 30 ++++++++++++++++++++++++------ src/wayland-private.h | 10 +++++++++- src/wayland-server.c | 18 ++++++++++++++++-- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/connection.c b/src/connection.c index 3ef8688d..593f52f3 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1494,7 +1494,7 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), - const char *queue_name) + const char *queue_name, int color) { int i; struct argument_details arg; @@ -1512,17 +1512,28 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + fprintf(f, "%s[%7u.%03u] ", + color ? WL_DEBUG_COLOR_GREEN : "", + time / 1000, time % 1000); - fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000); + if (queue_name) { + fprintf(f, "%s{%s} ", + color ? WL_DEBUG_COLOR_YELLOW : "", + queue_name); + } - if (queue_name) - fprintf(f, "{%s} ", queue_name); - - fprintf(f, "%s%s%s#%u.%s(", + fprintf(f, "%s%s%s%s%s%s%s#%u%s.%s%s(", + color ? WL_DEBUG_COLOR_RED : "", discarded ? "discarded " : "", + color ? WL_DEBUG_COLOR_RESET : "", send ? " -> " : "", - target->interface->name, target->id, - closure->message->name); + color ? WL_DEBUG_COLOR_BLUE : "", + target->interface->name, + color ? WL_DEBUG_COLOR_MAGENTA : "", + target->id, + color ? WL_DEBUG_COLOR_CYAN : "", + closure->message->name, + color ? WL_DEBUG_COLOR_RESET : ""); for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); @@ -1587,7 +1598,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, } } - fprintf(f, ")\n"); + fprintf(f, ")%s\n", color ? WL_DEBUG_COLOR_RESET : ""); if (fclose(f) == 0) { fprintf(stderr, "%s", buffer); diff --git a/src/wayland-client.c b/src/wayland-client.c index 25aa1cd4..d0913c52 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -115,6 +115,7 @@ struct wl_display { /** \endcond */ static int debug_client = 0; +static int debug_color = 0; /** * This helper function wakes up all threads that are @@ -936,7 +937,7 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, queue_name = wl_event_queue_get_name(queue); wl_closure_print(closure, &proxy->object, true, false, NULL, - queue_name); + queue_name, debug_color); } if (wl_closure_send(closure, proxy->display->connection)) { @@ -1229,10 +1230,23 @@ wl_display_connect_to_fd(int fd) { struct wl_display *display; const char *debug; + const char *no_color; + const char *force_color; + no_color = getenv("NO_COLOR"); + force_color = getenv("FORCE_COLOR"); debug = getenv("WAYLAND_DEBUG"); - if (debug && (strstr(debug, "client") || strstr(debug, "1"))) + if (debug && (strstr(debug, "client") || strstr(debug, "1"))) { debug_client = 1; + if (isatty(fileno(stderr))) + debug_color = 1; + } + + if (force_color && force_color[0] != '\0') + debug_color = 1; + + if (no_color && no_color[0] != '\0') + debug_color = 0; display = zalloc(sizeof *display); if (display == NULL) { @@ -1578,12 +1592,16 @@ queue_event(struct wl_display *display, int len) if (debug_client) { clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - - fprintf(stderr, "[%7u.%03u] discarded [%s]#%d.[event %d]" + fprintf(stderr, "%s[%7u.%03u] %sdiscarded %s[%s]%s#%d%s.[event %d]%s" "(%d fd, %d byte)\n", + debug_color ? WL_DEBUG_COLOR_GREEN : "", time / 1000, time % 1000, + debug_color ? WL_DEBUG_COLOR_RED : "", + debug_color ? WL_DEBUG_COLOR_BLUE : "", zombie ? "zombie" : "unknown", - id, opcode, + debug_color ? WL_DEBUG_COLOR_MAGENTA : "", id, + debug_color ? WL_DEBUG_COLOR_BLUE : "", opcode, + debug_color ? WL_DEBUG_COLOR_RESET : "", num_zombie_fds, size); } if (num_zombie_fds > 0) @@ -1668,7 +1686,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) !(proxy->dispatcher || proxy->object.implementation); wl_closure_print(closure, &proxy->object, false, discarded, - id_from_object, queue->name); + id_from_object, queue->name, debug_color); } if (proxy_destroyed) { diff --git a/src/wayland-private.h b/src/wayland-private.h index fe9120af..9aace67d 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -50,6 +50,14 @@ #define WL_BUFFER_DEFAULT_SIZE_POT 12 #define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT) +#define WL_DEBUG_COLOR_RESET "\e[0m" +#define WL_DEBUG_COLOR_RED "\e[31m" +#define WL_DEBUG_COLOR_GREEN "\e[32m" +#define WL_DEBUG_COLOR_YELLOW "\e[33m" +#define WL_DEBUG_COLOR_BLUE "\e[34m" +#define WL_DEBUG_COLOR_MAGENTA "\e[35m" +#define WL_DEBUG_COLOR_CYAN "\e[36m" + /** * Argument types used in signatures. */ @@ -230,7 +238,7 @@ void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), - const char *queue_name); + const char *queue_name, int color); void wl_closure_destroy(struct wl_closure *closure); diff --git a/src/wayland-server.c b/src/wayland-server.c index a538519e..96dd417b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -149,6 +149,7 @@ struct wl_protocol_logger { }; static int debug_server = 0; +static int debug_color = 0; static void log_closure(struct wl_resource *resource, @@ -160,7 +161,7 @@ log_closure(struct wl_resource *resource, struct wl_protocol_logger_message message; if (debug_server) - wl_closure_print(closure, object, send, false, NULL, NULL); + wl_closure_print(closure, object, send, false, NULL, NULL, debug_color); if (!wl_list_empty(&display->protocol_loggers)) { message.resource = resource; @@ -1168,10 +1169,23 @@ wl_display_create(void) { struct wl_display *display; const char *debug; + const char *no_color; + const char *force_color; + no_color = getenv("NO_COLOR"); + force_color = getenv("FORCE_COLOR"); debug = getenv("WAYLAND_DEBUG"); - if (debug && (strstr(debug, "server") || strstr(debug, "1"))) + if (debug && (strstr(debug, "server") || strstr(debug, "1"))) { debug_server = 1; + if (isatty(fileno(stderr))) + debug_color = 1; + } + + if (force_color && force_color[0] != '\0') + debug_color = 1; + + if (no_color && no_color[0] != '\0') + debug_color = 0; display = zalloc(sizeof *display); if (display == NULL) From 6281ccbd3d98ef0a6503425e3e7d705e3075e265 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Wed, 28 May 2025 21:40:17 +0300 Subject: [PATCH 1064/1152] client: fix conversion specifier in the discarded event log message Signed-off-by: Kirill Primak --- src/wayland-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index d0913c52..fe14a6b1 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1592,7 +1592,7 @@ queue_event(struct wl_display *display, int len) if (debug_client) { clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(stderr, "%s[%7u.%03u] %sdiscarded %s[%s]%s#%d%s.[event %d]%s" + fprintf(stderr, "%s[%7u.%03u] %sdiscarded %s[%s]%s#%u%s.[event %d]%s" "(%d fd, %d byte)\n", debug_color ? WL_DEBUG_COLOR_GREEN : "", time / 1000, time % 1000, From 1bee7aa4a7d6590f882a61a29da16316ba27c600 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Thu, 12 Sep 2024 20:36:47 +0200 Subject: [PATCH 1065/1152] cursor: Fix undefined behavior with huge names If an index.theme contains a theme name which gets close to INT_MAX, then creation of full path can lead to a signed integer overflow, which is undefined behavior. Fix this by turning one of the values to size_t. Easy solution for a probably never occurring issue. Signed-off-by: Tobias Stoeckmann --- cursor/xcursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 2b6c47d5..b852a1f9 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -571,7 +571,7 @@ xcursor_build_theme_dir(const char *dir, const char *theme) * add space for any needed directory separators, one per component, * and one for the trailing null */ - full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1; + full_size = (size_t) 1 + homelen + 1 + dirlen + 1 + themelen + 1; full = malloc(full_size); if (!full) return NULL; From ce0ac4f29e720688ea94fbe412a0b332304d8ee6 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Thu, 12 Sep 2024 20:52:15 +0200 Subject: [PATCH 1066/1152] cursor: Gracefully handle out of memory condition If the full path could not be constructed, avoid calling opendir(NULL) which, depending on library, might trigger undefined behavior. Signed-off-by: Tobias Stoeckmann --- cursor/xcursor.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index b852a1f9..f7156cdb 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -686,11 +686,15 @@ load_all_cursors_from_dir(const char *path, int size, void *user_data) { FILE *f; - DIR *dir = opendir(path); + DIR *dir; struct dirent *ent; char *full; struct xcursor_images *images; + if (!path) + return; + + dir = opendir(path); if (!dir) return; From 5c2f31d8d6e5f24962300f4608a0d6f887ca3bea Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Thu, 12 Sep 2024 22:05:52 +0200 Subject: [PATCH 1067/1152] cursor: Gracefully handle huge cursor files If cursor files require more than INT_MAX bytes, it is possible to trigger out of boundary writes. Since these sizes are most likely not desired anyway, gracefully handle these situations like out of memory errors. Signed-off-by: Tobias Stoeckmann --- cursor/wayland-cursor.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 636f5166..f3fef157 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -27,6 +27,7 @@ #include "xcursor.h" #include "wayland-cursor.h" #include "wayland-client.h" +#include #include #include #include @@ -284,7 +285,8 @@ wl_cursor_create_from_xcursor_images(struct xcursor_images *images, { struct cursor *cursor; struct cursor_image *image; - int i, size; + size_t size; + int i; cursor = malloc(sizeof *cursor); if (!cursor) @@ -314,7 +316,12 @@ wl_cursor_create_from_xcursor_images(struct xcursor_images *images, image->image.hotspot_y = images->images[i]->yhot; image->image.delay = images->images[i]->delay; - size = image->image.width * image->image.height * 4; + size = (size_t) image->image.width * image->image.height * 4; + if (size > INT_MAX) { + free(image); + break; + } + image->offset = shm_pool_allocate(theme->pool, size); if (image->offset < 0) { free(image); @@ -389,6 +396,9 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) if (!theme) return NULL; + if (size < 0 || (size > 0 && INT_MAX / size / 4 < size)) + return NULL; + if (!name) name = "default"; From 2978fd701a6987668a4ff41f9434f6c0da705596 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Thu, 12 Sep 2024 22:18:30 +0200 Subject: [PATCH 1068/1152] cursor: Ignore invalid cursor files The header offset must not be smaller than file header length. Ignore such invalid files. Signed-off-by: Tobias Stoeckmann --- cursor/xcursor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index f7156cdb..6e54cdbd 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -259,6 +259,8 @@ xcursor_read_file_header(FILE *file) return NULL; if (!xcursor_read_uint(file, &head.ntoc)) return NULL; + if (head.header < XCURSOR_FILE_HEADER_LEN) + return NULL; skip = head.header - XCURSOR_FILE_HEADER_LEN; if (skip) if (fseek(file, skip, SEEK_CUR) == EOF) From 0de833da296e59e2495738afc450d1d3cb0314b3 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Thu, 12 Sep 2024 23:07:45 +0200 Subject: [PATCH 1069/1152] cursor: Properly check realloc for errors Do not override realloc's input pointer before checking for errors, otherwise it's not possible to keep old value, as intended. Signed-off-by: Tobias Stoeckmann --- cursor/wayland-cursor.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index f3fef157..89ecc9a1 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -351,6 +351,8 @@ load_callback(struct xcursor_images *images, void *data) { struct wl_cursor_theme *theme = data; struct wl_cursor *cursor; + struct wl_cursor **p; + size_t s; if (wl_cursor_theme_get_cursor(theme, images->name)) { xcursor_images_destroy(images); @@ -360,15 +362,14 @@ load_callback(struct xcursor_images *images, void *data) cursor = wl_cursor_create_from_xcursor_images(images, theme); if (cursor) { - theme->cursor_count++; - theme->cursors = - realloc(theme->cursors, - theme->cursor_count * sizeof theme->cursors[0]); + s = theme->cursor_count + 1; + p = realloc(theme->cursors, s * sizeof theme->cursors[0]); - if (theme->cursors == NULL) { - theme->cursor_count--; + if (p == NULL) { free(cursor); } else { + theme->cursor_count = s; + theme->cursors = p; theme->cursors[theme->cursor_count - 1] = cursor; } } From 387adc6a794df6bee114396612d5a6accab318c3 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Tue, 2 Mar 2021 23:24:16 -0500 Subject: [PATCH 1070/1152] server: Document wl_display_add_socket_auto The exact sequence of names tried has de facto become part of the API. Signed-off-by: Manuel Stoeckl --- src/wayland-server.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/wayland-server.c b/src/wayland-server.c index 96dd417b..15667644 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1808,6 +1808,24 @@ _wl_display_add_socket(struct wl_display *display, struct wl_socket *s) return 0; } + +/** Automatically pick a Wayland display socket for the clients to connect to. + * + * \param display Wayland display to which the socket should be added. + * \return The socket name if success. NULL if failed. + * + * This adds a Unix socket to Wayland display which can be used by clients to + * connect to Wayland display. The name of the socket is chosen automatically + * as the first available name in the sequence "wayland-0", "wayland-1", + * "wayland-2", ..., "wayland-32". + * + * The string returned by this function is owned by the library and should + * not be freed. + * + * \sa wl_display_add_socket + * + * \memberof wl_display + */ WL_EXPORT const char * wl_display_add_socket_auto(struct wl_display *display) { From 4a0c4e211949bd58fa7e6105487b8dac0d4cfd1c Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Tue, 2 Mar 2021 22:04:58 -0500 Subject: [PATCH 1071/1152] doc: Further explain typical display socket lookup This change mentions the case where WAYLAND_SOCKET is used, which helps people avoid just testing 'getenv(WAYLAND_DISPLAY)' to see if a Wayland compositor is available; Signed-off-by: Manuel Stoeckl --- doc/publican/sources/Protocol.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml index 692f17eb..e4087e9f 100644 --- a/doc/publican/sources/Protocol.xml +++ b/doc/publican/sources/Protocol.xml @@ -97,7 +97,9 @@ in the environment). Beginning in Wayland 1.15, implementations can optionally support server socket endpoints located at arbitrary locations in the filesystem by setting WAYLAND_DISPLAY - to the absolute path at which the server endpoint listens. + to the absolute path at which the server endpoint listens. The socket may + also be provided through file descriptor inheritance, in which case + WAYLAND_SOCKET is set. Every message is structured as 32-bit words; values are represented in the From ca83185e8a28017ff3a2f9edccaa5d35bb86f1d7 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Thu, 19 Dec 2024 21:44:00 -0500 Subject: [PATCH 1072/1152] tests: Make `tests` dict elements dicts themselves Previously each value was a list of extra sources. The next commit will add an additional field to each test, so they need to be dicts themselves. Signed-off-by: Matt Turner --- tests/meson.build | 161 ++++++++++++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 64 deletions(-) diff --git a/tests/meson.build b/tests/meson.build index 2c22b82a..cf3c4e87 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -96,72 +96,105 @@ if get_option('scanner') endif tests = { - 'array-test': [], - 'client-test': [ wayland_server_protocol_h ], - 'display-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - tests_server_protocol_h, - tests_client_protocol_c, - tests_protocol_c, - ], - 'connection-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'event-loop-test': [ wayland_server_protocol_h ], - 'fixed-test': [], - 'interface-test': [ wayland_client_protocol_h ], - 'list-test': [], - 'map-test': [], - 'sanity-test' : [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'socket-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'queue-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'signal-test': [ wayland_server_protocol_h ], - 'newsignal-test': [ - # wayland-server.c is needed here to access wl_priv_* functions - files('../src/wayland-server.c'), - wayland_server_protocol_h, - ], - 'resources-test': [ wayland_server_protocol_h ], - 'message-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'compositor-introspection-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'protocol-logger-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'headers-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - 'headers-protocol-test.c', - wayland_client_protocol_core_h, - wayland_server_protocol_core_h, - 'headers-protocol-core-test.c', - ], - 'os-wrappers-test': [], - 'proxy-test': [ - wayland_client_protocol_h, - wayland_server_protocol_h, - ], - 'enum-validator-test': [], + 'array-test': {}, + 'client-test': { + 'extra_sources': [ wayland_server_protocol_h ], + }, + 'display-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + tests_server_protocol_h, + tests_client_protocol_c, + tests_protocol_c, + ], + }, + 'connection-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'event-loop-test': { + 'extra_sources': [ wayland_server_protocol_h ], + }, + 'fixed-test': {}, + 'interface-test': { + 'extra_sources': [ wayland_client_protocol_h ], + }, + 'list-test': {}, + 'map-test': {}, + 'sanity-test' : { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'socket-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'queue-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'signal-test': { + 'extra_sources': [ wayland_server_protocol_h ], + }, + 'newsignal-test': { + 'extra_sources': [ + # wayland-server.c is needed here to access wl_priv_* functions + files('../src/wayland-server.c'), + wayland_server_protocol_h, + ], + }, + 'resources-test': { + 'extra_sources': [ wayland_server_protocol_h ], + }, + 'message-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'compositor-introspection-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'protocol-logger-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'headers-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + 'headers-protocol-test.c', + wayland_client_protocol_core_h, + wayland_server_protocol_core_h, + 'headers-protocol-core-test.c', + ], + }, + 'os-wrappers-test': {}, + 'proxy-test': { + 'extra_sources': [ + wayland_client_protocol_h, + wayland_server_protocol_h, + ], + }, + 'enum-validator-test': {}, } -foreach test_name, test_extra_sources: tests +foreach test_name, test_extras : tests + test_extra_sources = test_extras.get('extra_sources', []) test_sources = [ test_name + '.c' ] + test_extra_sources test_deps = [test_runner_dep, epoll_dep] bin = executable(test_name, test_sources, dependencies: test_deps) From 6c1da920185955f7c86af38787c8889203ec3fcb Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Thu, 19 Dec 2024 21:48:49 -0500 Subject: [PATCH 1073/1152] tests: Add support for specifying runtime dependencies Signed-off-by: Matt Turner --- tests/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/meson.build b/tests/meson.build index cf3c4e87..44f1233d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -195,12 +195,14 @@ tests = { foreach test_name, test_extras : tests test_extra_sources = test_extras.get('extra_sources', []) + test_runtime_deps = test_extras.get('runtime_deps', []) test_sources = [ test_name + '.c' ] + test_extra_sources test_deps = [test_runner_dep, epoll_dep] bin = executable(test_name, test_sources, dependencies: test_deps) test( test_name, bin, + depends: test_runtime_deps, env: [ 'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()), 'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()), From fdac631d1744d50e6e470bb78bf5057664967e32 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Thu, 19 Dec 2024 21:49:02 -0500 Subject: [PATCH 1074/1152] tests: Depend on exec-fd-leak-checker Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/514 Signed-off-by: Matt Turner --- tests/meson.build | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/meson.build b/tests/meson.build index 44f1233d..6ada5202 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -54,7 +54,7 @@ tests_protocol_c = custom_target( output: 'tests-protocol.c' ) -executable( +exec_fd_leak_checker = executable( 'exec-fd-leak-checker', 'exec-fd-leak-checker.c', dependencies: test_runner_dep @@ -129,6 +129,7 @@ tests = { wayland_client_protocol_h, wayland_server_protocol_h, ], + 'runtime_deps': [ exec_fd_leak_checker ], }, 'socket-test': { 'extra_sources': [ @@ -183,7 +184,9 @@ tests = { 'headers-protocol-core-test.c', ], }, - 'os-wrappers-test': {}, + 'os-wrappers-test': { + 'runtime_deps': [ exec_fd_leak_checker ], + }, 'proxy-test': { 'extra_sources': [ wayland_client_protocol_h, From 53fbc2b0c1dc70b3a96740ab0ceff6a9fe09b940 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Thu, 19 Dec 2024 21:51:50 -0500 Subject: [PATCH 1075/1152] egl: Make `wayland-egl symbols check` depend on `wayland_egl` Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/515 Signed-off-by: Matt Turner --- egl/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/egl/meson.build b/egl/meson.build index 5363e808..b72c7a46 100644 --- a/egl/meson.build +++ b/egl/meson.build @@ -22,6 +22,7 @@ if get_option('tests') test( 'wayland-egl symbols check', find_program('wayland-egl-symbols-check'), + depends: wayland_egl, env: [ 'WAYLAND_EGL_LIB=@0@'.format(wayland_egl_shared.full_path()), 'NM=@0@'.format(nm_path) From ba9f9a446f7462a7b41b34e585c7beca020d12f7 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 12 Jun 2025 14:37:32 +0300 Subject: [PATCH 1076/1152] doc: add a section on color management I think the docbook deserves an introduction to how color management is designed in Wayland, aimed at people who are familiar with pixels but new to the topic. Signed-off-by: Pekka Paalanen --- doc/publican/sources/Color.xml | 139 +++++++++++++++++++++++++++++++ doc/publican/sources/Wayland.xml | 1 + doc/publican/sources/meson.build | 1 + 3 files changed, 141 insertions(+) create mode 100644 doc/publican/sources/Color.xml diff --git a/doc/publican/sources/Color.xml b/doc/publican/sources/Color.xml new file mode 100644 index 00000000..ceee779e --- /dev/null +++ b/doc/publican/sources/Color.xml @@ -0,0 +1,139 @@ + + +%BOOK_ENTITIES; +]> + + + Color management + +
+ Overview + + + Color management in Wayland considers only displays. All pictures in + Wayland are always display-referred, meaning that the pixel values are + intended as-is for some specific display where they would produce the + light emissions (stimuli) the picture's + author desired. Wayland does not support displaying "raw" camera or + scanner images as they are not display-referred, nor are they even + pictures without complex and subjective processing. + + + Stimuli — the picture itself — are only half of the picture reproduction. + The other half is the environment where a display is viewed. A striking + example is comparing a brightly lit office to a dark movie theater, the + stimuli required to produce a good reading of the picture is greatly + different. Therefore display-referred does not include only the display + but the viewing environment as well. + + + Window systems have been very well capable of operating without any + explicit consideration to color management. This is because there used to + be the implicit assumption of the standard display, the sRGB display, + which all computer monitors implemented, more or less. The viewing + environment was and still is accounted by adjusting the display and/or the + room to produce a workable experience. Pictures are authored on a computer + system by drawing, painting and adjusting the picture until it looks right + on the author's monitor. This implicitly builds the standard display and + environment assumption into the picture data. Deviations from the sRGB + specification were minor enough that they often did not matter if not in a + professional context like the printing industry. Displaying video material + required some more attention to the details, because video and television + standards differ enough from the sRGB display. What really made explicit + color management a hard requirement for entertainment is the coming of + wide color gamut (WCG) and high dynamic range (HDR) materials and + displays. + + + The color management design in Wayland follows the general Wayland design + principles: compositors tell clients what would be the optimal thing to + do, clients tell the compositors what kind of pictures they are actually + producing, and then compositors display those pictures the best they can. + +
+ +
+ Protocol Interfaces + + + Color management interfaces in Wayland and divided into two protocols: + color-management + and + color-representation. + They are designed to work together, but they can also be used + independently when the other one is not needed. + + +
+ Color-management + + + Color management protocol has two main purposes. First, it puts the + responsibility of color management on the compositor. This means that + clients do not necessarily need to care about color management at all, + and can display just fine by using the traditional standard display + assumption even when the actual display is wildly different. Clients + can also choose to target some other assumed display and let the + compositor handle it, or they can explicitly render for the actual + display at hand. Second, when the window system has multiple different + monitors, and a wl_surface happens to span more than one monitor, the + compositor can display the surface content correctly on all spanned + monitors simultaneously, as much as physically possible. + + + Color-management protocol concentrates on colorimetry: when you have a + pixel with RGB values, what stimulus do those values represent. The + stimulus definition follows the CIE 1931 two-degree observer model. Some + core concepts here are color primaries, white point, transfer function, + and dynamic range. The viewing environment is represented in an + extremely simplified way as the reference white luminance. The + connection between pixel RGB values and stimulus plus viewing + environment is recorded in an image description + object. Clients can create image description objects and tag + wl_surfaces with them, to indicate what kind of surface + content there will be. Clients can also ask what image description the + compositor would prefer to have on the wl_surface, and that + preference can change over time, e.g. when the wl_surface + is moved from one + wl_output to another. Following the compositor's preference + may provide advantages in image quality and power consumption. + + + Image description objects can come in two flavors: parametric and + ICC-based. The above was written with parametric image descriptions in + mind, and they have first-class support for HDR. ICC-based image + descriptions are wrapping an ICC profile and have no other data. ICC + profiles are the standard tool for standard dynamic range (SDR) display + color management. This means the capabilities between the two flavors + differ, and one cannot always be replaced by the other. Compositor + support for each flavor is optional. + +
+ +
+ Color-representation + + + Color-representation protocol deals with (potentially sub-sampled) + YCbCr-RGB conversion, quantization range, and the inclusion of alpha in + the RGB color channels, a.k.a. pre-multiplication. There are several + different specifications on how an YCbCr-like (including ICtCp) signal, + with chroma sub-sampling or not, is created from a full-resolution RGB + image. Again, a client can tag a wl_surface with + color-representation metadata to tell the compositor what kind of pixel + data will be displayed through the wl_surface. + + + The main purpose of color-representation is to correctly off-load the + YCbCr-RGB conversion to the compositor, which can then opportunistically + off-load it further to very power-efficient fixed-function circuitry in + a display controller. This can significantly reduce power consumption + when watching videos compared to using a GPU for the same, and on some + embedded hardware platforms it is a hard requirement for processing high + resolution video. + +
+
+
diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/sources/Wayland.xml index 0457c15c..7593097e 100644 --- a/doc/publican/sources/Wayland.xml +++ b/doc/publican/sources/Wayland.xml @@ -12,6 +12,7 @@ + diff --git a/doc/publican/sources/meson.build b/doc/publican/sources/meson.build index 52f3a681..a53b3890 100644 --- a/doc/publican/sources/meson.build +++ b/doc/publican/sources/meson.build @@ -54,6 +54,7 @@ publican_sources = [ 'Protocol.xml', 'Xwayland.xml', 'Compositors.xml', + 'Color.xml', 'Client.xml', 'Server.xml' ] From adf84614ca6189fa4efc522408ffbbc4b27ae497 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Wed, 14 Aug 2024 21:14:49 -0400 Subject: [PATCH 1077/1152] connection: Do not busy-loop if a message exceeds the buffer size If the length of a message exceeds the maximum length of the buffer, the buffer size will reach its maximum value and stay there forever, with no message ever being successfully processed. Since libwayland uses level-triggered epoll, this will cause the compositor to loop forever and consume CPU time. In libwayland 1.22 and below, there was an explicit check that caused messages exceeding 4096 bytes to result in an EOVERFLOW error, preventing the loop. However, this check was removed between d074d5290263 ("connection: Dynamically resize connection buffers"). To prevent this problem, always limit the size of messages to 4096 bytes. Since the default and minimum buffer size is 4096 bytes, this ensures that a single message will always fit in the buffer. It would be possible to allow larger messages if the buffer size was larger, but the maximum size of a message should not depend on the buffer size chosen by the compositor. Rejecting messages that exceed 4092 bytes seems to have the advantage of reserving 4 bits, not 3, in the size field for future use. However, message sizes in the range [0x0, 0x7] are invalid, so one can obtain a fourth bit by negating the meaning of bit 12 if bits 0 through 11 (inclusive) are 0. Allowing 4096-byte messages provides the far more important advantage that regressions compared to 1.22 are impossible and regressions compared to 1.23 are extremely unlikely. The only case where a regression is possible is: - The receiving side is using libwayland 1.23. - The sending side is either using libwayland 1.23 or is not using libwayland. - The sender sends a message exceeding 4096 bytes. - If the sender of the large message is the client, the server has increased the buffer size from the default value. This combination is considered extremely unlikely, as libwayland 1.22 and below would disconnect upon receiving such a large message. 4096-byte messages, however, have always worked, so there was no reason to avoid sending them. Fixes: d074d5290263 ("connection: Dynamically resize connection buffers"). Fixes: #494 Signed-off-by: Demi Marie Obenour --- src/wayland-client.c | 22 ++++++++++++++++++++++ src/wayland-private.h | 3 +++ src/wayland-server.c | 23 +++++++++++++++++++++++ src/wayland-util.h | 8 ++++++++ 4 files changed, 56 insertions(+) diff --git a/src/wayland-client.c b/src/wayland-client.c index fe14a6b1..c8633046 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1578,6 +1578,28 @@ queue_event(struct wl_display *display, int len) id = p[0]; opcode = p[1] & 0xffff; size = p[1] >> 16; + + /* + * If the message is larger than the maximum size of the + * connection buffer, the connection buffer will fill to + * its max size and stay there, with no message ever + * successfully being processed. If the user of + * libwayland-client uses a level-triggered event loop, + * this will cause the client to enter a loop that + * consumes CPU. To avoid this, immediately drop the + * connection. Since the maximum size of a message should + * not depend on the max buffer size chosen by the client, + * always compare the message size against the + * limit enforced by libwayland 1.22 and below (4096), + * rather than the actual value the client chose. + */ + if (size > WL_MAX_MESSAGE_SIZE) { + wl_log("Message length %u exceeds limit %d\n", + size, WL_MAX_MESSAGE_SIZE); + errno = E2BIG; + return -1; + } + if (len < size) return 0; diff --git a/src/wayland-private.h b/src/wayland-private.h index 9aace67d..d7ba9dae 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -49,6 +49,9 @@ #define WL_CLOSURE_MAX_ARGS 20 #define WL_BUFFER_DEFAULT_SIZE_POT 12 #define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT) +#if WL_BUFFER_DEFAULT_MAX_SIZE < WL_MAX_MESSAGE_SIZE +# error default buffer cannot hold maximum-sized message +#endif #define WL_DEBUG_COLOR_RESET "\e[0m" #define WL_DEBUG_COLOR_RED "\e[31m" diff --git a/src/wayland-server.c b/src/wayland-server.c index 15667644..482743b3 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -398,6 +398,29 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) wl_connection_copy(connection, p, sizeof p); opcode = p[1] & 0xffff; size = p[1] >> 16; + + /* + * If the message is larger than the maximum size of the + * connection buffer, the connection buffer will fill to + * its max size and stay there, with no message ever + * successfully being processed. Since libwayland-server + * uses level-triggered epoll, it will cause the server to + * enter a loop that consumes CPU. To avoid this, + * immediately disconnect the client with a protocol + * error. Since the maximum size of a message should not + * depend on the buffer size chosen by the compositor, + * always compare the message size against the + * limit enforced by libwayland 1.22 and below (4096), + * rather than the actual value the compositor chose. + */ + if (size > WL_MAX_MESSAGE_SIZE) { + wl_resource_post_error(client->display_resource, + WL_DISPLAY_ERROR_INVALID_METHOD, + "message length %u exceeds %d", + size, WL_MAX_MESSAGE_SIZE); + break; + } + if (len < size) break; diff --git a/src/wayland-util.h b/src/wayland-util.h index 4540f040..98c72fde 100644 --- a/src/wayland-util.h +++ b/src/wayland-util.h @@ -90,6 +90,14 @@ extern "C" { */ struct wl_object; +/** + * The maximum size of a protocol message. + * + * If a message size exceeds this value, the connection will be dropped. + * Servers will send an invalid_method error before disconnecting. + */ +#define WL_MAX_MESSAGE_SIZE 4096 + /** * Protocol message signature * From eecf3f7635586c41d985e0f443fd4f8930751487 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 21 Jun 2025 13:38:28 +0200 Subject: [PATCH 1078/1152] build: re-open main branch for regular development Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a3126b63..37c14687 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.23.91', + version: '1.24.90', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ From 90187031e6ee0ab5cf2b3ec243a314babf4e8561 Mon Sep 17 00:00:00 2001 From: ykla Date: Sun, 22 Jun 2025 15:09:50 +0000 Subject: [PATCH 1079/1152] ci: upgrade FreeBSD to 14.2 Signed-off-by: ykla --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eb6fb0b4..26ceae1f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ include: # API changes. If you need new features from ci-templates you must bump # this to the current SHA you require from the ci-templates repo, however # be aware that you may need to account for API changes when doing so. - ref: f210ea84576f756816da37908771edcee14ef7e6 + ref: 32afe5644697e503af18a736587c8619fa036a72 file: - '/templates/debian.yml' - '/templates/freebsd.yml' @@ -306,11 +306,11 @@ armv7-release-debian-build: .os-freebsd: variables: BUILD_OS: freebsd - FDO_DISTRIBUTION_VERSION: "13.2" + FDO_DISTRIBUTION_VERSION: "14.2" FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2023-08-02.0" + FDO_DISTRIBUTION_TAG: "2025-06-23.1" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false" From cd0d1543c093d079ecf3444a16a4dcb02007a62a Mon Sep 17 00:00:00 2001 From: ykla Date: Sun, 20 Jul 2025 02:09:35 +0000 Subject: [PATCH 1080/1152] ci: upgrade FreeBSD to 14.3 Signed-off-by: ykla yklaxds@gmail.com --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 26ceae1f..eeed7899 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ include: # API changes. If you need new features from ci-templates you must bump # this to the current SHA you require from the ci-templates repo, however # be aware that you may need to account for API changes when doing so. - ref: 32afe5644697e503af18a736587c8619fa036a72 + ref: 48c2c583a865bd59be21e8938df247faf460099c file: - '/templates/debian.yml' - '/templates/freebsd.yml' @@ -306,11 +306,11 @@ armv7-release-debian-build: .os-freebsd: variables: BUILD_OS: freebsd - FDO_DISTRIBUTION_VERSION: "14.2" + FDO_DISTRIBUTION_VERSION: "14.3" FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2025-06-23.1" + FDO_DISTRIBUTION_TAG: "2025-07-20.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false" From 264da6a92b48ef41661021236c5d51ca52722309 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Wed, 16 Jul 2025 22:29:40 +0800 Subject: [PATCH 1081/1152] cursor: Free theme when size check fails to avoid memory leak Signed-off-by: YaoBing Xiao --- cursor/wayland-cursor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c index 89ecc9a1..2e21db73 100644 --- a/cursor/wayland-cursor.c +++ b/cursor/wayland-cursor.c @@ -398,7 +398,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) return NULL; if (size < 0 || (size > 0 && INT_MAX / size / 4 < size)) - return NULL; + goto err; if (!name) name = "default"; @@ -409,7 +409,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) theme->pool = shm_pool_create(shm, size * size * 4); if (!theme->pool) - goto out_error_pool; + goto err; xcursor_load_theme(name, size, load_callback, theme); @@ -421,7 +421,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) return theme; -out_error_pool: +err: free(theme); return NULL; } From 77730f10a0eaac1c654d1bdc689783292bdb5f2d Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Tue, 17 Sep 2024 17:27:37 -0600 Subject: [PATCH 1082/1152] connection: Add a function to parse WAYLAND_DEBUG tokens Add a new function, wl_check_env_token, to scan for a token in a comma-separated string. Change wl_display_create in wayland-server.c and wl_display_connect_to_fd in wayland-client.c to use that instead of a simple substring search. This means that WAYLAND_DEBUG will accept a value like "client,server" but not "clientserver". But, this will make it easier to add other tokens without worrying about overlap between them. Signed-off-by: Kyle Brenneman --- src/connection.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/wayland-client.c | 2 +- src/wayland-private.h | 3 +++ src/wayland-server.c | 2 +- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/connection.c b/src/connection.c index 593f52f3..9c6a6b01 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1491,6 +1491,48 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) return result; } +bool +wl_check_env_token(const char *env, const char *token) +{ + const char *ptr = env; + size_t token_len; + + if (env == NULL) + return false; + + token_len = strlen(token); + + // Scan the string for comma-separated tokens and look for a match. + while (true) { + const char *end; + size_t len; + + // Skip over any leading separators. + while (*ptr == ',') + ptr++; + + if (*ptr == '\x00') + return false; + + end = strchr(ptr + 1, ','); + + // If there isn't another separarator, then the rest of the string + // is one token. + if (end == NULL) + return (strcmp(ptr, token) == 0); + + len = end - ptr; + if (len == token_len && memcmp(ptr, token, len) == 0) { + return true; + } + + // Skip to the next token. + ptr += len; + } + + return false; +} + void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), diff --git a/src/wayland-client.c b/src/wayland-client.c index c8633046..c0b361f0 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1236,7 +1236,7 @@ wl_display_connect_to_fd(int fd) no_color = getenv("NO_COLOR"); force_color = getenv("FORCE_COLOR"); debug = getenv("WAYLAND_DEBUG"); - if (debug && (strstr(debug, "client") || strstr(debug, "1"))) { + if (debug && (wl_check_env_token(debug, "client") || wl_check_env_token(debug, "1"))) { debug_client = 1; if (isatty(fileno(stderr))) debug_color = 1; diff --git a/src/wayland-private.h b/src/wayland-private.h index d7ba9dae..d0e4cfc6 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -237,6 +237,9 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection); int wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); +bool +wl_check_env_token(const char *env, const char *token); + void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, diff --git a/src/wayland-server.c b/src/wayland-server.c index 482743b3..c81d98f1 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1198,7 +1198,7 @@ wl_display_create(void) no_color = getenv("NO_COLOR"); force_color = getenv("FORCE_COLOR"); debug = getenv("WAYLAND_DEBUG"); - if (debug && (strstr(debug, "server") || strstr(debug, "1"))) { + if (debug && (wl_check_env_token(debug, "server") || wl_check_env_token(debug, "1"))) { debug_server = 1; if (isatty(fileno(stderr))) debug_color = 1; From 4673ef7e9ce5de21051b64c39816a98187611966 Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Tue, 10 Sep 2024 14:36:06 -0600 Subject: [PATCH 1083/1152] connection: Add a thread ID to WAYLAND_DEBUG output. If WAYLAND_DEBUG contains the token "thread_id", and gettid() is available, then include the current thread ID in the output from wl_closure_print. If multiple threads are sending requests, then those requests can get interleaved. That's usually fine, but for wl_surface requests and commits, that can cause problems ranging from incorrect behavior to protocol errors. Being able to see which requests are sent by different threads would make such problems much easier to diagnose. Signed-off-by: Kyle Brenneman --- meson.build | 1 + src/connection.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/meson.build b/meson.build index 37c14687..ce386a4c 100644 --- a/meson.build +++ b/meson.build @@ -46,6 +46,7 @@ have_funcs = [ 'memfd_create', 'mremap', 'strndup', + 'gettid', ] foreach f: have_funcs config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f)) diff --git a/src/connection.c b/src/connection.c index 9c6a6b01..2d1e8d1d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -26,6 +26,8 @@ #define _GNU_SOURCE +#include "../config.h" + #include #include #include @@ -1538,6 +1540,9 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), const char *queue_name, int color) { +#if defined(HAVE_GETTID) + static int include_tid = -1; +#endif // defined(HAVE_GETTID) int i; struct argument_details arg; const char *signature = closure->message->signature; @@ -1558,6 +1563,18 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, color ? WL_DEBUG_COLOR_GREEN : "", time / 1000, time % 1000); +#if defined(HAVE_GETTID) + if (include_tid < 0) { + include_tid = wl_check_env_token(getenv("WAYLAND_DEBUG"), "thread_id"); + } + + if (include_tid) { + fprintf(f, "%sTID#%d ", + color ? WL_DEBUG_COLOR_CYAN : "", + (int) gettid()); + } +#endif + if (queue_name) { fprintf(f, "%s{%s} ", color ? WL_DEBUG_COLOR_YELLOW : "", From d81525a235e48cc5de3e4005a16ddb1fbdfd9d7c Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 2 Jul 2025 12:15:33 +0200 Subject: [PATCH 1084/1152] client: add wl_display_dispatch_pending_single As well as wl_display_dispatch_queue_pending_single. The motivation is writing libwayland bindings for a dynamic language with exceptions/non-local returns. Since it is invalid for a wl_dispatcher_func_t callback provided to libwayland to not return, there is no way to prevent dispatching of further events in the case of an exception in the dynamic language event handler. Furthermore, since creating/destroying Wayland objects in an event handler affects the dispatching of subsequent events by libwayland, it is not possible to collect Wayland events in a queue outside libwayland and dispatch them one-by-one after wl_display_dispatch_pending() returns. Adding libwayland API to dispatch at most one pending event solves this problem cleanly. The bindings can have libwayland dispatch a single event, wait for wl_display_dispatch_pending_single() to return, run the dynamic language event handler (which may longjmp away), and continue the loop for as long as there are more events to dispatch. References: https://codeberg.org/ifreund/janet-wayland Signed-off-by: Isaac Freund --- src/wayland-client-core.h | 7 ++++ src/wayland-client.c | 75 +++++++++++++++++++++++++++++++++++++++ tests/display-test.c | 69 +++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index 970e6254..e0523e49 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -268,9 +268,16 @@ int wl_display_dispatch_queue_pending(struct wl_display *display, struct wl_event_queue *queue); +int +wl_display_dispatch_queue_pending_single(struct wl_display *display, + struct wl_event_queue *queue); + int wl_display_dispatch_pending(struct wl_display *display); +int +wl_display_dispatch_pending_single(struct wl_display *display); + int wl_display_get_error(struct wl_display *display); diff --git a/src/wayland-client.c b/src/wayland-client.c index c0b361f0..ed686b5c 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1882,6 +1882,34 @@ err: return -1; } + +static int +dispatch_queue_single(struct wl_display *display, struct wl_event_queue *queue) +{ + if (display->last_error) + goto err; + + while (!wl_list_empty(&display->display_queue.event_list)) { + dispatch_event(display, &display->display_queue); + if (display->last_error) + goto err; + } + + if (!wl_list_empty(&queue->event_list)) { + dispatch_event(display, queue); + if (display->last_error) + goto err; + return 1; + } else { + return 0; + } + +err: + errno = display->last_error; + + return -1; +} + /** Prepare to read events from the display's file descriptor to a queue * * \param display The display context object @@ -2212,6 +2240,34 @@ wl_display_dispatch_queue_pending(struct wl_display *display, return ret; } +/** Dispatch at most one pending event in an event queue + * + * \param display The display context object + * \param queue The event queue to dispatch + * \return The number of dispatched events (0 or 1) on success or -1 on failure + * + * Dispatch at most one pending event for objects assigned to the given + * event queue. On failure -1 is returned and errno set appropriately. + * If there are no events queued, this function returns immediately. + * + * \memberof wl_display + * \since 1.25.0 + */ +WL_EXPORT int +wl_display_dispatch_queue_pending_single(struct wl_display *display, + struct wl_event_queue *queue) +{ + int ret; + + pthread_mutex_lock(&display->mutex); + + ret = dispatch_queue_single(display, queue); + + pthread_mutex_unlock(&display->mutex); + + return ret; +} + /** Process incoming events * * \param display The display context object @@ -2272,6 +2328,25 @@ wl_display_dispatch_pending(struct wl_display *display) &display->default_queue); } +/** Dispatch at most one pending event in the default event queue. + * + * \param display The display context object + * \return The number of dispatched events (0 or 1) on success or -1 on failure + * + * Dispatch at most one pending event for objects assigned to the default + * event queue. On failure -1 is returned and errno set appropriately. + * If there are no events queued, this function returns immediately. + * + * \memberof wl_display + * \since 1.25.0 + */ +WL_EXPORT int +wl_display_dispatch_pending_single(struct wl_display *display) +{ + return wl_display_dispatch_queue_pending_single(display, + &display->default_queue); +} + /** Retrieve the last error that occurred on a display * * \param display The display context object diff --git a/tests/display-test.c b/tests/display-test.c index 89606c73..fe78b521 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1695,6 +1695,75 @@ TEST(global_remove) display_destroy(d); } +static void +dispatch_single_read_events(struct wl_display *d) +{ + if (wl_display_prepare_read(d) < 0) { + return; + } + + int ret = 0; + do { + ret = wl_display_flush(d); + } while (ret < 0 && (errno == EINTR || errno == EAGAIN)); + assert(ret >= 0); + + struct pollfd pfd[1]; + pfd[0].fd = wl_display_get_fd(d); + pfd[0].events = POLLIN; + + do { + ret = poll(pfd, 1, -1); + } while (ret < 0 && errno == EINTR); + assert(ret > 0); + + wl_display_read_events(d); +} + +static void +dispatch_single_client(void) +{ + struct client *c = client_connect(); + + assert(wl_display_dispatch_pending_single(c->wl_display) == 0); + + struct wl_registry *registry = wl_display_get_registry(c->wl_display); + + dispatch_single_read_events(c->wl_display); + + // [1815110.061] {Default Queue} wl_registry#3.global(1, "test", 1) + assert(wl_display_dispatch_pending_single(c->wl_display) == 1); + + dispatch_single_read_events(c->wl_display); + + // [1815110.067] {Default Queue} wl_registry#3.global(2, "wl_seat", 1) + assert(wl_display_dispatch_pending_single(c->wl_display) == 1); + + // No more events + assert(wl_display_dispatch_pending_single(c->wl_display) == 0); + + wl_registry_destroy(registry); + + client_disconnect(c); +} + +TEST(dispatch_single) +{ + struct display *d = display_create(); + + struct wl_global *global = wl_global_create(d->wl_display, + &wl_seat_interface, + 1, d, bind_seat); + + client_create_noarg(d, dispatch_single_client); + + display_run(d); + + wl_global_destroy(global); + + display_destroy(d); +} + static void terminate_display(void *arg) { From dfab16e2363ec171b6db3c447dd5dfd2a9e89115 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 26 Nov 2025 09:09:58 +0100 Subject: [PATCH 1085/1152] protocol: add new formats Generated from libdrm 2.4.129. Signed-off-by: Julian Orth --- protocol/wayland.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index bee74a10..5a6a189d 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -434,6 +434,26 @@ + + + + + + + + + + + + + + + + + + + + From c8a09967039f14081d1a36c5899cebed95210443 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 28 Oct 2025 12:11:10 +0100 Subject: [PATCH 1086/1152] build: Bump to meson version 0.64.0 This version will be required in the next commit. Bumps the CI image to get the required version from the debian package instead of from pip. Removes the bindir builtin directory from pkgconfig.generate() which is deprecated since 0.62.0. It will be automatically included when referenced. Use `meson setup` everywhere instead of relying on deprecated automatic detection of the setup command. Signed-off-by: Sebastian Wick --- .gitlab-ci.yml | 16 +++++++--------- meson.build | 2 +- src/meson.build | 1 - 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eeed7899..bde40e7f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -78,11 +78,10 @@ workflow: variables: BUILD_OS: debian FDO_DISTRIBUTION_VERSION: bookworm - FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' - FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson~=0.57.2' + FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson ninja-build' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2025-01-21.1" + FDO_DISTRIBUTION_TAG: "2025-10-28.1" .debian-x86_64: extends: @@ -223,11 +222,10 @@ armv7-debian-container_prep: - .ci-rules stage: "Build and test" script: - - cd "$BUILDDIR" - - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} .. - - ninja -k0 -j${FDO_CI_CONCURRENT:-4} - - meson test --num-processes ${FDO_CI_CONCURRENT:-4} - - ninja clean + - meson setup $BUILDDIR --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} + - ninja -C $BUILDDIR -k0 -j${FDO_CI_CONCURRENT:-4} + - meson test -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4} + - ninja -C $BUILDDIR clean artifacts: name: wayland-$CI_JOB_NAME when: always @@ -250,7 +248,7 @@ armv7-debian-container_prep: # the workspace to see details about the failed tests. - | set +e - /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}" + /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson setup $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}" /app/vmctl exec "meson test --print-errorlogs -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4}" && touch .tests-successful set -ex scp -r vm:$BUILDDIR/meson-logs . diff --git a/meson.build b/meson.build index ce386a4c..c96ca29f 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'wayland', 'c', version: '1.24.90', license: 'MIT', - meson_version: '>= 0.57.0', + meson_version: '>= 0.64.0', default_options: [ 'warning_level=2', 'buildtype=debugoptimized', diff --git a/src/meson.build b/src/meson.build index 984e34ab..b3b9ea57 100644 --- a/src/meson.build +++ b/src/meson.build @@ -66,7 +66,6 @@ if get_option('scanner') variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()), - 'bindir=' + join_paths('${prefix}', get_option('bindir')), 'wayland_scanner=${bindir}/wayland-scanner' ], filebase: 'wayland-scanner' From bbb5fa66a7fe53c492e4cc2e616c4ada38712542 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 28 Oct 2025 00:36:53 +0100 Subject: [PATCH 1087/1152] doc: Refactor the build system for complete build dir docs By structuring things differently, it becomes possible to have a complete build of the docs in the build dir, without having to install anything. Signed-off-by: Sebastian Wick --- doc/doxygen/meson.build | 12 -- doc/doxygen/xml/Client/meson.build | 1 - doc/doxygen/xml/Server/meson.build | 1 - doc/doxygen/xml/meson.build | 20 --- doc/publican/{sources => }/Architecture.xml | 0 doc/publican/{sources => }/Author_Group.xml | 0 doc/publican/{sources => }/Book_Info.xml | 0 doc/publican/{sources => }/Client.xml | 0 doc/publican/{sources => }/Color.xml | 0 doc/publican/{sources => }/Compositors.xml | 0 doc/publican/{sources => }/Foreword.xml | 0 doc/publican/{sources => }/Introduction.xml | 0 doc/publican/{sources => }/Preface.xml | 0 doc/publican/{sources => }/Protocol.xml | 0 .../{sources => }/Revision_History.xml | 0 doc/publican/{sources => }/Server.xml | 0 doc/publican/{sources => }/Wayland.ent | 0 doc/publican/{sources => }/Wayland.xml | 0 doc/publican/{sources => }/Xwayland.xml | 0 doc/publican/{sources => html}/css/brand.css | 0 doc/publican/{sources => html}/css/common.css | 0 .../{sources => html}/css/default.css | 0 doc/publican/{sources => html}/css/epub.css | 0 doc/publican/html/css/meson.build | 14 +++ doc/publican/{sources => html}/css/print.css | 0 .../{sources => html}/images/icon.svg | 0 doc/publican/html/images/meson.build | 28 +++++ .../html/images}/wayland-architecture.gv | 0 .../{sources => html}/images/wayland.png | Bin .../html/images}/x-architecture.gv | 0 .../images/xwayland-architecture.png | Bin doc/publican/meson.build | 106 +++++++++++++--- doc/publican/sources/meson.build | 114 ------------------ .../{ => xsl}/doxygen-to-publican.xsl | 0 doc/publican/{ => xsl}/merge-mapcoords.xsl | 0 .../protocol-interfaces-to-docbook.xsl | 0 .../{ => xsl}/protocol-to-docbook.xsl | 0 meson.build | 6 +- 38 files changed, 138 insertions(+), 164 deletions(-) rename doc/publican/{sources => }/Architecture.xml (100%) rename doc/publican/{sources => }/Author_Group.xml (100%) rename doc/publican/{sources => }/Book_Info.xml (100%) rename doc/publican/{sources => }/Client.xml (100%) rename doc/publican/{sources => }/Color.xml (100%) rename doc/publican/{sources => }/Compositors.xml (100%) rename doc/publican/{sources => }/Foreword.xml (100%) rename doc/publican/{sources => }/Introduction.xml (100%) rename doc/publican/{sources => }/Preface.xml (100%) rename doc/publican/{sources => }/Protocol.xml (100%) rename doc/publican/{sources => }/Revision_History.xml (100%) rename doc/publican/{sources => }/Server.xml (100%) rename doc/publican/{sources => }/Wayland.ent (100%) rename doc/publican/{sources => }/Wayland.xml (100%) rename doc/publican/{sources => }/Xwayland.xml (100%) rename doc/publican/{sources => html}/css/brand.css (100%) rename doc/publican/{sources => html}/css/common.css (100%) rename doc/publican/{sources => html}/css/default.css (100%) rename doc/publican/{sources => html}/css/epub.css (100%) create mode 100644 doc/publican/html/css/meson.build rename doc/publican/{sources => html}/css/print.css (100%) rename doc/publican/{sources => html}/images/icon.svg (100%) create mode 100644 doc/publican/html/images/meson.build rename doc/{doxygen/dot => publican/html/images}/wayland-architecture.gv (100%) rename doc/publican/{sources => html}/images/wayland.png (100%) rename doc/{doxygen/dot => publican/html/images}/x-architecture.gv (100%) rename doc/publican/{sources => html}/images/xwayland-architecture.png (100%) delete mode 100644 doc/publican/sources/meson.build rename doc/publican/{ => xsl}/doxygen-to-publican.xsl (100%) rename doc/publican/{ => xsl}/merge-mapcoords.xsl (100%) rename doc/publican/{ => xsl}/protocol-interfaces-to-docbook.xsl (100%) rename doc/publican/{ => xsl}/protocol-to-docbook.xsl (100%) diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build index 61126206..551bd4b4 100644 --- a/doc/doxygen/meson.build +++ b/doc/doxygen/meson.build @@ -1,16 +1,5 @@ # Here be dragons -dot_gv = { - 'wayland-architecture': files('dot/wayland-architecture.gv'), - 'x-architecture': files('dot/x-architecture.gv'), -} - -# This is a workaround for Meson's custom_target() directive, which -# currently does not support outputs pointing to a sub-directory -# XXX: try turning these into maps, so they can be indexed with picture name -dot_png = [] -dot_map = [] - doxygen_conf = configuration_data() doxygen_conf.set('VERSION', meson.project_version()) doxygen_conf.set('top_builddir', meson.project_build_root()) @@ -91,7 +80,6 @@ foreach f_name, sections: formats ], input: s_files, output: '@0@.stamp'.format(t_name), - depends: [dot_png, dot_map], build_by_default: true, ) endforeach diff --git a/doc/doxygen/xml/Client/meson.build b/doc/doxygen/xml/Client/meson.build index 849c30da..e51fccb6 100644 --- a/doc/doxygen/xml/Client/meson.build +++ b/doc/doxygen/xml/Client/meson.build @@ -11,7 +11,6 @@ tgt = custom_target( ], input: [ shared_files, client_files ], output: [ 'combine.xslt', 'index.xml' ], - depends: [dot_png, dot_map] ) doxygen_Client_combine_xslt = tgt[0] diff --git a/doc/doxygen/xml/Server/meson.build b/doc/doxygen/xml/Server/meson.build index 4792c1bc..5df97440 100644 --- a/doc/doxygen/xml/Server/meson.build +++ b/doc/doxygen/xml/Server/meson.build @@ -11,7 +11,6 @@ tgt = custom_target( ], input: [ shared_files, server_files ], output: [ 'combine.xslt', 'index.xml' ], - depends: [dot_png, dot_map] ) doxygen_Server_combine_xslt = tgt[0] diff --git a/doc/doxygen/xml/meson.build b/doc/doxygen/xml/meson.build index 6d55c53a..479af8e7 100644 --- a/doc/doxygen/xml/meson.build +++ b/doc/doxygen/xml/meson.build @@ -1,22 +1,2 @@ -# dot_png: list of PNG targets -# dot_map: list of MAP targets -foreach name, infile: dot_gv - dot_png += custom_target( - name + '.png', - command: [ dot, '-Tpng', '-o@OUTPUT@', '@INPUT@' ], - input: infile, - output: name + '.png', - install: true, - install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images') - ) - - dot_map += custom_target( - name + '.map', - command: [ dot, '-Tcmapx_np', '-o@OUTPUT@', '@INPUT@' ], - input: infile, - output: name + '.map', - ) -endforeach - subdir('Client') subdir('Server') diff --git a/doc/publican/sources/Architecture.xml b/doc/publican/Architecture.xml similarity index 100% rename from doc/publican/sources/Architecture.xml rename to doc/publican/Architecture.xml diff --git a/doc/publican/sources/Author_Group.xml b/doc/publican/Author_Group.xml similarity index 100% rename from doc/publican/sources/Author_Group.xml rename to doc/publican/Author_Group.xml diff --git a/doc/publican/sources/Book_Info.xml b/doc/publican/Book_Info.xml similarity index 100% rename from doc/publican/sources/Book_Info.xml rename to doc/publican/Book_Info.xml diff --git a/doc/publican/sources/Client.xml b/doc/publican/Client.xml similarity index 100% rename from doc/publican/sources/Client.xml rename to doc/publican/Client.xml diff --git a/doc/publican/sources/Color.xml b/doc/publican/Color.xml similarity index 100% rename from doc/publican/sources/Color.xml rename to doc/publican/Color.xml diff --git a/doc/publican/sources/Compositors.xml b/doc/publican/Compositors.xml similarity index 100% rename from doc/publican/sources/Compositors.xml rename to doc/publican/Compositors.xml diff --git a/doc/publican/sources/Foreword.xml b/doc/publican/Foreword.xml similarity index 100% rename from doc/publican/sources/Foreword.xml rename to doc/publican/Foreword.xml diff --git a/doc/publican/sources/Introduction.xml b/doc/publican/Introduction.xml similarity index 100% rename from doc/publican/sources/Introduction.xml rename to doc/publican/Introduction.xml diff --git a/doc/publican/sources/Preface.xml b/doc/publican/Preface.xml similarity index 100% rename from doc/publican/sources/Preface.xml rename to doc/publican/Preface.xml diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/Protocol.xml similarity index 100% rename from doc/publican/sources/Protocol.xml rename to doc/publican/Protocol.xml diff --git a/doc/publican/sources/Revision_History.xml b/doc/publican/Revision_History.xml similarity index 100% rename from doc/publican/sources/Revision_History.xml rename to doc/publican/Revision_History.xml diff --git a/doc/publican/sources/Server.xml b/doc/publican/Server.xml similarity index 100% rename from doc/publican/sources/Server.xml rename to doc/publican/Server.xml diff --git a/doc/publican/sources/Wayland.ent b/doc/publican/Wayland.ent similarity index 100% rename from doc/publican/sources/Wayland.ent rename to doc/publican/Wayland.ent diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/Wayland.xml similarity index 100% rename from doc/publican/sources/Wayland.xml rename to doc/publican/Wayland.xml diff --git a/doc/publican/sources/Xwayland.xml b/doc/publican/Xwayland.xml similarity index 100% rename from doc/publican/sources/Xwayland.xml rename to doc/publican/Xwayland.xml diff --git a/doc/publican/sources/css/brand.css b/doc/publican/html/css/brand.css similarity index 100% rename from doc/publican/sources/css/brand.css rename to doc/publican/html/css/brand.css diff --git a/doc/publican/sources/css/common.css b/doc/publican/html/css/common.css similarity index 100% rename from doc/publican/sources/css/common.css rename to doc/publican/html/css/common.css diff --git a/doc/publican/sources/css/default.css b/doc/publican/html/css/default.css similarity index 100% rename from doc/publican/sources/css/default.css rename to doc/publican/html/css/default.css diff --git a/doc/publican/sources/css/epub.css b/doc/publican/html/css/epub.css similarity index 100% rename from doc/publican/sources/css/epub.css rename to doc/publican/html/css/epub.css diff --git a/doc/publican/html/css/meson.build b/doc/publican/html/css/meson.build new file mode 100644 index 00000000..699d70ef --- /dev/null +++ b/doc/publican/html/css/meson.build @@ -0,0 +1,14 @@ +foreach src : files([ + 'brand.css', + 'common.css', + 'default.css', + 'epub.css', + 'print.css', +]) + name = fs.name(src) + publican_inputs += fs.copyfile( + name, + install: true, + install_dir: publican_install_prefix + '/html/css', + ) +endforeach diff --git a/doc/publican/sources/css/print.css b/doc/publican/html/css/print.css similarity index 100% rename from doc/publican/sources/css/print.css rename to doc/publican/html/css/print.css diff --git a/doc/publican/sources/images/icon.svg b/doc/publican/html/images/icon.svg similarity index 100% rename from doc/publican/sources/images/icon.svg rename to doc/publican/html/images/icon.svg diff --git a/doc/publican/html/images/meson.build b/doc/publican/html/images/meson.build new file mode 100644 index 00000000..98e5b937 --- /dev/null +++ b/doc/publican/html/images/meson.build @@ -0,0 +1,28 @@ +foreach src : files([ + 'icon.svg', + 'wayland.png', +]) + name = fs.name(src) + publican_inputs += fs.copyfile( + name, + install: true, + install_dir: publican_install_prefix + '/html/images', + ) +endforeach + +foreach src : files([ + 'wayland-architecture.gv', + 'x-architecture.gv', +]) + input = fs.name(src) + output = fs.stem(src) + '.png' + + publican_inputs += custom_target( + input + '.png', + command: [ dot, '-Tpng', '-o@OUTPUT@', '@INPUT@' ], + input: input, + output: output, + install: true, + install_dir: publican_install_prefix + '/html/images', + ) +endforeach diff --git a/doc/doxygen/dot/wayland-architecture.gv b/doc/publican/html/images/wayland-architecture.gv similarity index 100% rename from doc/doxygen/dot/wayland-architecture.gv rename to doc/publican/html/images/wayland-architecture.gv diff --git a/doc/publican/sources/images/wayland.png b/doc/publican/html/images/wayland.png similarity index 100% rename from doc/publican/sources/images/wayland.png rename to doc/publican/html/images/wayland.png diff --git a/doc/doxygen/dot/x-architecture.gv b/doc/publican/html/images/x-architecture.gv similarity index 100% rename from doc/doxygen/dot/x-architecture.gv rename to doc/publican/html/images/x-architecture.gv diff --git a/doc/publican/sources/images/xwayland-architecture.png b/doc/publican/html/images/xwayland-architecture.png similarity index 100% rename from doc/publican/sources/images/xwayland-architecture.png rename to doc/publican/html/images/xwayland-architecture.png diff --git a/doc/publican/meson.build b/doc/publican/meson.build index eac3e9b2..83556f0d 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -1,6 +1,92 @@ -merge_mapcoords_xsl = files('merge-mapcoords.xsl') +proto_to_docboox_xsl = files('xsl/protocol-to-docbook.xsl') +proto_iface_to_docboox_xsl = files('xsl/protocol-interfaces-to-docbook.xsl') +merge_mapcoords_xsl = files('xsl/merge-mapcoords.xsl') +to_publican_xsl = files('xsl/doxygen-to-publican.xsl') -subdir('sources') +publican_inputs = [] + +foreach src : files([ + 'Wayland.xml', # must be first in publican_inputs + 'Wayland.ent', + 'Book_Info.xml', + 'Author_Group.xml', + 'Foreword.xml', + 'Preface.xml', + 'Revision_History.xml', + 'Protocol.xml', + 'Xwayland.xml', + 'Compositors.xml', + 'Color.xml', + 'Client.xml', + 'Server.xml', +]) + name = fs.name(src) + publican_inputs += fs.copyfile(name) +endforeach + +publican_inputs += custom_target( + 'ProtocolSpec.xml', + command: [ xsltproc, '-o', '@OUTPUT@', proto_to_docboox_xsl, '@INPUT@' ], + input: wayland_protocol_xml, + output: 'ProtocolSpec.xml' +) + +publican_inputs += custom_target( + 'ProtocolInterfaces.xml', + command: [ xsltproc, '-o', '@OUTPUT@', proto_iface_to_docboox_xsl, '@INPUT@' ], + input: wayland_protocol_xml, + output: 'ProtocolInterfaces.xml' +) + +ClientAPI_combined = custom_target( + 'ClientAPI-combined', + command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], + input: [ doxygen_Client_combine_xslt, doxygen_Client_index_xml ], + output: 'ClientAPI-combined.xml' +) + +publican_inputs += custom_target( + 'ClientAPI.xml', + command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Client', to_publican_xsl, '@INPUT@' ], + input: ClientAPI_combined, + output: 'ClientAPI.xml' +) + +ServerAPI_combined = custom_target( + 'ServerAPI-combined', + command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], + input: [ doxygen_Server_combine_xslt, doxygen_Server_index_xml ], + output: 'ServerAPI-combined.xml' +) + +publican_inputs += custom_target( + 'ServerAPI.xml', + command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Server', to_publican_xsl, '@INPUT@' ], + input: ServerAPI_combined, + output: 'ServerAPI.xml' +) + +foreach src : files([ + 'Architecture.xml', + 'Introduction.xml' +]) + name = fs.name(src) + publican_inputs += custom_target( + name, + command: [ + xsltproc, + '-o', '@OUTPUT@', + '--stringparam', 'basedir', '.', + merge_mapcoords_xsl, + '@INPUT@', + ], + input: [name], + output: [name], + ) +endforeach + +subdir('html/css') +subdir('html/images') custom_target( 'Wayland-docbook-html', @@ -14,19 +100,11 @@ custom_target( '--stringparam', 'html.stylesheet=css/default.css', '-o', '@OUTPUT@', 'html', - '@INPUT@' - ], - input: publican_processed_main, - output: publican_html_dir, - depend_files: publican_copied_sources, - depends: [ - publican_processed_targets, - ClientAPI_xml, - ServerAPI_xml, - ProtocolSpec_xml, - ProtocolInterfaces_xml + '@INPUT0@' ], + input: publican_inputs, + output: 'html', build_by_default: true, install: true, - install_dir: publican_install_prefix + install_dir: publican_install_prefix, ) diff --git a/doc/publican/sources/meson.build b/doc/publican/sources/meson.build deleted file mode 100644 index a53b3890..00000000 --- a/doc/publican/sources/meson.build +++ /dev/null @@ -1,114 +0,0 @@ -ProtocolSpec_xml = custom_target( - 'ProtocolSpec.xml', - command: [ xsltproc, '-o', '@OUTPUT@', files('../protocol-to-docbook.xsl'), '@INPUT@' ], - input: wayland_protocol_xml, - output: 'ProtocolSpec.xml' -) - -ProtocolInterfaces_xml = custom_target( - 'ProtocolInterfaces.xml', - command: [ xsltproc, '-o', '@OUTPUT@', files('../protocol-interfaces-to-docbook.xsl'), '@INPUT@' ], - input: wayland_protocol_xml, - output: 'ProtocolInterfaces.xml' -) - -ClientAPI_combined = custom_target( - 'ClientAPI-combined', - command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], - input: [ doxygen_Client_combine_xslt, doxygen_Client_index_xml ], - output: 'ClientAPI-combined.xml' -) - -to_publican_xsl = files('../doxygen-to-publican.xsl') - -ClientAPI_xml = custom_target( - 'ClientAPI.xml', - command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Client', to_publican_xsl, '@INPUT@' ], - input: ClientAPI_combined, - output: 'ClientAPI.xml' -) - -ServerAPI_combined = custom_target( - 'ServerAPI-combined', - command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], - input: [ doxygen_Server_combine_xslt, doxygen_Server_index_xml ], - output: 'ServerAPI-combined.xml' -) - -ServerAPI_xml = custom_target( - 'ServerAPI.xml', - command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Server', to_publican_xsl, '@INPUT@' ], - input: ServerAPI_combined, - output: 'ServerAPI.xml' -) - - -publican_sources = [ - 'Wayland.ent', - # 'Wayland.xml', # handled specially - 'Book_Info.xml', - 'Author_Group.xml', - 'Foreword.xml', - 'Preface.xml', - 'Revision_History.xml', - 'Protocol.xml', - 'Xwayland.xml', - 'Compositors.xml', - 'Color.xml', - 'Client.xml', - 'Server.xml' -] - -publican_processed_main = configure_file( - input: 'Wayland.xml', - output: 'Wayland.xml', - copy: true -) - -publican_copied_sources = [] -foreach src: publican_sources - publican_copied_sources += configure_file( - input: src, - output: src, - copy: true - ) -endforeach - -publican_processed_sources = [ - 'Architecture.xml', - 'Introduction.xml' -] - -publican_processed_targets = [] -foreach src: publican_processed_sources - publican_processed_targets += custom_target( - src, - command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'basedir', '.', merge_mapcoords_xsl, '@INPUT@' ], - input: src, - output: src - ) -endforeach - -publican_css_sources = files([ - 'css/brand.css', - 'css/common.css', - 'css/default.css', - 'css/epub.css', - 'css/print.css' -]) - -install_data( - publican_css_sources, - install_dir: join_paths(publican_install_prefix, publican_html_dir, 'css') -) - -publican_img_sources = files([ - 'images/icon.svg', - 'images/wayland.png', - 'images/xwayland-architecture.png' -]) - -install_data( - publican_img_sources, - install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images') -) diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/xsl/doxygen-to-publican.xsl similarity index 100% rename from doc/publican/doxygen-to-publican.xsl rename to doc/publican/xsl/doxygen-to-publican.xsl diff --git a/doc/publican/merge-mapcoords.xsl b/doc/publican/xsl/merge-mapcoords.xsl similarity index 100% rename from doc/publican/merge-mapcoords.xsl rename to doc/publican/xsl/merge-mapcoords.xsl diff --git a/doc/publican/protocol-interfaces-to-docbook.xsl b/doc/publican/xsl/protocol-interfaces-to-docbook.xsl similarity index 100% rename from doc/publican/protocol-interfaces-to-docbook.xsl rename to doc/publican/xsl/protocol-interfaces-to-docbook.xsl diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/xsl/protocol-to-docbook.xsl similarity index 100% rename from doc/publican/protocol-to-docbook.xsl rename to doc/publican/xsl/protocol-to-docbook.xsl diff --git a/meson.build b/meson.build index c96ca29f..7ad5ac06 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,10 @@ project( 'c_std=c99', ] ) + +fs = import('fs') +pkgconfig = import('pkgconfig') + wayland_version = meson.project_version().split('.') config_h = configuration_data() @@ -106,8 +110,6 @@ configure_file( configuration: config_h, ) -pkgconfig = import('pkgconfig') - wayland_protocol_xml = files('protocol/wayland.xml') root_inc = include_directories('.') From 99638501a1314e68c79176fa2cafa3bbe6cf55ea Mon Sep 17 00:00:00 2001 From: Joshua Watt Date: Mon, 10 Nov 2025 14:57:06 -0700 Subject: [PATCH 1088/1152] tests/event-loop-test: Remove event loop timer test The event loop timer test has very precise sequencing and timing constraints, which make it difficult to pass reliably on loaded systems. Since this test isn't providing much value, remove it to prevent the erroneous errors. Signed-off-by: Joshua Watt --- tests/event-loop-test.c | 43 ----------------------------------------- 1 file changed, 43 deletions(-) diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c index a51ba8fb..be15a34e 100644 --- a/tests/event-loop-test.c +++ b/tests/event-loop-test.c @@ -238,49 +238,6 @@ TEST(event_loop_multiple_same_signals) wl_event_loop_destroy(loop); } -static int -timer_callback(void *data) -{ - int *got_it = data; - - ++(*got_it); - - return 1; -} - -TEST(event_loop_timer) -{ - struct wl_event_loop *loop = wl_event_loop_create(); - struct wl_event_source *source1, *source2; - int got_it = 0; - - source1 = wl_event_loop_add_timer(loop, timer_callback, &got_it); - assert(source1); - wl_event_source_timer_update(source1, 20); - - source2 = wl_event_loop_add_timer(loop, timer_callback, &got_it); - assert(source2); - wl_event_source_timer_update(source2, 100); - - /* Check that the timer marked for 20 msec from now fires within 30 - * msec, and that the timer marked for 100 msec is expected to fire - * within an additional 90 msec. (Some extra wait time is provided to - * account for reasonable code execution / thread preemption delays.) */ - - wl_event_loop_dispatch(loop, 0); - assert(got_it == 0); - wl_event_loop_dispatch(loop, 30); - assert(got_it == 1); - wl_event_loop_dispatch(loop, 0); - assert(got_it == 1); - wl_event_loop_dispatch(loop, 90); - assert(got_it == 2); - - wl_event_source_remove(source1); - wl_event_source_remove(source2); - wl_event_loop_destroy(loop); -} - #define MSEC_TO_USEC(msec) ((msec) * 1000) struct timer_update_context { From 5b59b34a2732348204d1affccc02fcac5affe255 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 29 Dec 2025 11:10:19 +0200 Subject: [PATCH 1089/1152] editorconfig: indent .xsl with 2 spaces The XSL files are mostly indented with 2 spaces. Using the default editorconfig rules in VSCode constantly tries to mix in tabs. Add the 2-space rule for .xsl files to fix this. The .xsl files, like .xml files, use a tab character in place of 8 spaces. This complicates things, and the new rule will prefer just spaces. To keep the existing sometimes-tab-indented code looking right, the tab width must be explicitly set to 8. Signed-off-by: Pekka Paalanen --- .editorconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.editorconfig b/.editorconfig index d92e5e96..cd9aa7f6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,11 @@ indent_style = tab indent_size = 2 tab_width = 8 +[*.xsl] +indent_style = space +indent_size = 2 +tab_width = 8 + [*.py] indent_style = space indent_size = 4 From 0519f2fbf88c7c8c6a729109ed7f81bd703d9837 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sat, 27 Dec 2025 20:02:36 +0200 Subject: [PATCH 1090/1152] doc: remove HTML_TIMESTAMP to fix the Doxygen message: warning: Tag 'HTML_TIMESTAMP' at line 8 of file '-' has become obsolete. To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u" Observed with Doxygen 1.9.8. Signed-off-by: Pekka Paalanen --- doc/doxygen/wayland.doxygen.in | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in index 60c5fbbb..ac4207d4 100644 --- a/doc/doxygen/wayland.doxygen.in +++ b/doc/doxygen/wayland.doxygen.in @@ -5,7 +5,6 @@ OUTPUT_DIRECTORY = @top_builddir@/doc/doxygen JAVADOC_AUTOBRIEF = YES TAB_SIZE = 8 QUIET = YES -HTML_TIMESTAMP = YES GENERATE_LATEX = NO MAN_LINKS = NO PREDEFINED = WL_EXPORT= \ From 573c95cb1a5f42c882936c4a6d29fbbfd1d8a50a Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sat, 27 Dec 2025 21:07:06 +0200 Subject: [PATCH 1091/1152] doc/xsl: fix malformed For all requests and events that do not have any arguments, enabling XML validation would lead to many errors like this: /home/pq/git/wayland/build/doc/publican/Wayland.xml:5287: element variablelist: validity error : Element variablelist content does not follow the DTD, expecting (blockinfo? , (title , titleabbrev?)? , (caution | important | note | tip | warning | literallayout | programlisting | programlistingco | screen | screenco | screenshot | synopsis | cmdsynopsis | funcsynopsis | classsynopsis | fieldsynopsis | constructorsynopsis | destructorsynopsis | methodsynopsis | formalpara | para | simpara | address | blockquote | graphic | graphicco | mediaobject | mediaobjectco | informalequation | informalexample | informalfigure | informaltable | anchor | bridgehead | remark | highlights | abstract | authorblurb | epigraph | indexterm | beginpage)* , varlistentry+), got The reason is that a without any inside it is illegal. If there are no at all, do not emit the list paragraph. Signed-off-by: Pekka Paalanen --- doc/publican/xsl/protocol-to-docbook.xsl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/publican/xsl/protocol-to-docbook.xsl b/doc/publican/xsl/protocol-to-docbook.xsl index 79c938bb..92f8d677 100644 --- a/doc/publican/xsl/protocol-to-docbook.xsl +++ b/doc/publican/xsl/protocol-to-docbook.xsl @@ -186,11 +186,13 @@ - - - - - - + + + + + + + From e1e8ccd4aea229718d65f8f3008dcec3ff7d04c5 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sat, 27 Dec 2025 21:44:29 +0200 Subject: [PATCH 1092/1152] doc: reinstate image maps This fixes the errors during the compilation of Architecture.xml that the .map files cannot be found. As a result, the architure diagrams become clickable in the HTML document once again. Signed-off-by: Pekka Paalanen --- doc/publican/html/images/meson.build | 7 +++++++ doc/publican/meson.build | 12 +++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/publican/html/images/meson.build b/doc/publican/html/images/meson.build index 98e5b937..de4cc181 100644 --- a/doc/publican/html/images/meson.build +++ b/doc/publican/html/images/meson.build @@ -25,4 +25,11 @@ foreach src : files([ install: true, install_dir: publican_install_prefix + '/html/images', ) + + publican_image_maps += custom_target( + input + '.map', + command: [ dot, '-Tcmapx_np', '-o@OUTPUT@', '@INPUT@' ], + input: input, + output: fs.stem(src) + '.map', + ) endforeach diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 83556f0d..64932800 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -4,6 +4,7 @@ merge_mapcoords_xsl = files('xsl/merge-mapcoords.xsl') to_publican_xsl = files('xsl/doxygen-to-publican.xsl') publican_inputs = [] +publican_image_maps = [] foreach src : files([ 'Wayland.xml', # must be first in publican_inputs @@ -66,6 +67,9 @@ publican_inputs += custom_target( output: 'ServerAPI.xml' ) +subdir('html/css') +subdir('html/images') + foreach src : files([ 'Architecture.xml', 'Introduction.xml' @@ -76,18 +80,16 @@ foreach src : files([ command: [ xsltproc, '-o', '@OUTPUT@', - '--stringparam', 'basedir', '.', + '--stringparam', 'basedir', meson.current_build_dir() / 'html', merge_mapcoords_xsl, '@INPUT@', ], - input: [name], + input: src, output: [name], + depends: publican_image_maps, ) endforeach -subdir('html/css') -subdir('html/images') - custom_target( 'Wayland-docbook-html', command: [ From d1b8f352c3f68c8394f0a3f362d19ac18479d95f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 10:36:16 +0200 Subject: [PATCH 1093/1152] server: fix wl_signal_add Doxygen warning $ meson compile -C build -v xml-Server-doc INFO: autodetecting backend as ninja INFO: calculating backend command to run: /usr/bin/ninja -C /home/pq/git/wayland/build -v doc/doxygen/xml/Server/combine.xslt doc/doxygen/xml/Server/index.xml ninja: Entering directory `/home/pq/git/wayland/build' [1/1] /home/pq/git/wayland/doc/doxygen/gen-doxygen.py --builddir=doc/doxygen/xml/Server --section=Server --output-format=xml doc/doxygen/wayland.doxygen ../doc/doxygen/../../src/wayland-util.h ../doc/doxygen/../../src/event-loop.c ../doc/doxygen/../../src/wayland-server.c ../doc/doxygen/../../src/wayland-server.h ../doc/doxygen/../../src/wayland-server-core.h ../doc/doxygen/../../src/wayland-shm.c /home/pq/git/wayland/src/wayland-server-core.h:394: warning: explicit link request to 'wl_signal_add' could not be resolved I don't know why, but the "explicit link" mark-up fails, while the automatic link mark-up works. This warning disappears. Signed-off-by: Pekka Paalanen --- src/wayland-server-core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index c2dcc218..586ecfbc 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -391,7 +391,7 @@ wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size); * object destruction. * * Clients should create wl_listener objects manually and can register them as - * listeners to signals using #wl_signal_add, assuming the signal is + * listeners to signals using wl_signal_add(), assuming the signal is * directly accessible. For opaque structs like wl_event_loop, adding a * listener should be done through provided accessor methods. A listener can * only listen to one signal at a time. From 256f853261982dc41fa8750dcd2cdac8b26ecbc7 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 10:46:06 +0200 Subject: [PATCH 1094/1152] doc: fix Xwayland image validity xmllint complained: element imageobjectco: validity error : Element imageobjectco content does not follow the DTD, expecting (areaspec , imageobject , calloutlist*), got (imageobject ) This image has no callouts (clickable items explained in the text), so it must not use the tags that assume callouts. I probably cargo-culted this from the X11 and Wayland diagrams which have callouts when writing Xwayland.xml. Signed-off-by: Pekka Paalanen --- doc/publican/Xwayland.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/doc/publican/Xwayland.xml b/doc/publican/Xwayland.xml index 79155598..cc5a73dd 100644 --- a/doc/publican/Xwayland.xml +++ b/doc/publican/Xwayland.xml @@ -77,13 +77,11 @@
Xwayland architecture diagram - - - - - - - + + + + +
An X11 application connects to Xwayland just like it would connect to any From da2e9b5c63e76c9c03e1e45bc3fcacd9f35a0b80 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 11:25:31 +0200 Subject: [PATCH 1095/1152] doc/xsl: include static inline functions When generating documentation, xmllint complained: element link: validity error : IDREF attribute linkend references an unknown ID "Server-structwl__signal_1afe73f44f7f1b517c9c0ba90829c93309" element link: validity error : IDREF attribute linkend references an unknown ID "Server-structwl__signal_1afe73f44f7f1b517c9c0ba90829c93309" element link: validity error : IDREF attribute linkend references an unknown ID "Server-structwl__signal_1aa8bcd3b8e250cfe35ed064d5af589096" These were referring to wl_signal_add() and wl_signal_emit() I think, which are static inlines in a public header. The XSLT ignored static functions, probably assuming that they cannot be public API. Internal (static) functions are present in the Doxygen XML, so they do need to be excluded. Now we include static functions if their body is in a header. We de not scan private headers, so they must be public API. Comparing the final generated HTML documentation, these functions are added to both Client and Server APIs: wl_fixed_to_double wl_fixed_from_double wl_fixed_to_int wl_fixed_from_int These functions are added to the Server API: wl_signal_init wl_signal_add wl_signal_get wl_signal_emit Signed-off-by: Pekka Paalanen --- doc/publican/xsl/doxygen-to-publican.xsl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/publican/xsl/doxygen-to-publican.xsl b/doc/publican/xsl/doxygen-to-publican.xsl index e13dcd76..0387372f 100644 --- a/doc/publican/xsl/doxygen-to-publican.xsl +++ b/doc/publican/xsl/doxygen-to-publican.xsl @@ -101,8 +101,16 @@ - + From 7736d8793bb190ce92d33584d54a6ab60f653871 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 11:32:43 +0200 Subject: [PATCH 1096/1152] build/doc: explain two XML conversions Now that I figured out what these do, I might as well add comments about it for others. The target names are changed to be more descriptive of what the target does. Signed-off-by: Pekka Paalanen --- doc/publican/meson.build | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 64932800..9704f29a 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -39,29 +39,33 @@ publican_inputs += custom_target( output: 'ProtocolInterfaces.xml' ) +# Doxygen generates a myriad of files, and offers an XSLT +# to combine them all into one. This does the combining. +# The result is still Doxygen XML. ClientAPI_combined = custom_target( - 'ClientAPI-combined', + 'ClientAPI-combine-doxygen-files', command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], input: [ doxygen_Client_combine_xslt, doxygen_Client_index_xml ], output: 'ClientAPI-combined.xml' ) +# This converts Doxygen XML to DocBook XML. publican_inputs += custom_target( - 'ClientAPI.xml', + 'ClientAPI-doxygen-to-docbook', command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Client', to_publican_xsl, '@INPUT@' ], input: ClientAPI_combined, output: 'ClientAPI.xml' ) ServerAPI_combined = custom_target( - 'ServerAPI-combined', + 'ServerAPI-combine-doxygen-files', command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ], input: [ doxygen_Server_combine_xslt, doxygen_Server_index_xml ], output: 'ServerAPI-combined.xml' ) publican_inputs += custom_target( - 'ServerAPI.xml', + 'ServerAPI-doxygen-to-docbook', command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Server', to_publican_xsl, '@INPUT@' ], input: ServerAPI_combined, output: 'ServerAPI.xml' From 12ec67aed517b88375d10c73ce7380ef52e515c4 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 12:33:32 +0200 Subject: [PATCH 1097/1152] server: document listener fields and a vfunc Adding these simple documentation comments allows us to have meaningful link targets in the generated API documentation. That will help getting rid of broken links which cause XML validation to fail. Signed-off-by: Pekka Paalanen --- src/wayland-server-core.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 586ecfbc..8b69d0d5 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -360,6 +360,7 @@ void wl_client_add_resource_created_listener(struct wl_client *client, struct wl_listener *listener); +/** Callback function type for wl_client_for_each_resource() */ typedef enum wl_iterator_result (*wl_client_for_each_resource_iterator_func_t)( struct wl_resource *resource, void *user_data); @@ -430,7 +431,10 @@ wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size); * \sa wl_signal */ struct wl_listener { + /** Part of wl_signal::listener_list */ struct wl_list link; + + /** Callback function pointer */ wl_notify_func_t notify; }; From 4216a08b964207d2c7f588489de7c0da4388e7f7 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 12:36:40 +0200 Subject: [PATCH 1098/1152] doc/xsl: rearrange member doc generation Creating an empty is illegal. This can already be seen in the XSL anywhere it is generated. The used XSL programming pattern requires the look-up conditions to be repeated between the and tags. Usually this is not a problem, but the conditions for memberdef is too much to copy around. The conditions between the if and the apply-templates have already diverged, causing validation errors (that are currently suppressed). Rearrange the XSL so that the applicable memberdef are stored in a variable, so that both the if and the apply-templates operate on the exact same set of matches. This avoids emitting empty . As a result, the members of structures wl_argument, wl_interface, wl_message, and wl_listener newly appear in the documentation. Signed-off-by: Pekka Paalanen --- doc/publican/xsl/doxygen-to-publican.xsl | 31 ++++++++++++++---------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/publican/xsl/doxygen-to-publican.xsl b/doc/publican/xsl/doxygen-to-publican.xsl index 0387372f..d7f29597 100644 --- a/doc/publican/xsl/doxygen-to-publican.xsl +++ b/doc/publican/xsl/doxygen-to-publican.xsl @@ -9,9 +9,7 @@
Functions - - - +
@@ -99,9 +97,10 @@ - - - + + (@kind != 'function' and normalize-space(briefdescription) != '') + ]" /> + + + + + + + + + + @@ -125,7 +135,6 @@ - @@ -145,11 +154,7 @@ - - - - - +
From f9e6b471f75e29e6b5bc2c0a88cb0ef3f706b742 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 28 Dec 2025 12:44:26 +0200 Subject: [PATCH 1099/1152] doc: validate doc XML again Now that all XML validation errors have been fixed, it is time to turn the validation back on to make sure the errors stay out. Signed-off-by: Pekka Paalanen --- doc/publican/meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 9704f29a..6be7bad3 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -98,7 +98,6 @@ custom_target( 'Wayland-docbook-html', command: [ xmlto, - '--skip-validation', '--stringparam', 'chunker.output.encoding=UTF-8', '--stringparam', 'chunk.section.depth=0', '--stringparam', 'toc.section.depth=1', From f72e3fae4a56f1e15e667cf4efc2271b8f12e31b Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Sat, 3 Jan 2026 15:16:13 +0100 Subject: [PATCH 1100/1152] server: document protocol logger callback function This fixes a validation error in the documentation which are not fatal. The idea is the same as in 12ec67a ("server: document listener fields and a vfunc"), which seems to have missed the reference to the wl_protocol_logger_func_t from the note in wl_log_func_t. Signed-off-by: Sebastian Wick --- src/wayland-server-core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 8b69d0d5..c8a64772 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -713,6 +713,7 @@ struct wl_protocol_logger_message { const union wl_argument *arguments; }; +/** Callback function type for wl_display_add_protocol_logger() */ typedef void (*wl_protocol_logger_func_t)(void *user_data, enum wl_protocol_logger_type direction, const struct wl_protocol_logger_message *message); From 8c0947892b56c3df792b8557cbf33b54038d8a1c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 27 Dec 2025 12:41:06 +0100 Subject: [PATCH 1101/1152] tests: cast pid_t and struct timeval fields before printing The exact type behind these might depend on the architecture. For instance, on ARMv7, struct timeval fields are long long int instead of long int: FAILED: tests/libtest-runner.a.p/test-compositor.c.o cc -Itests/libtest-runner.a.p -Itests -I../tests -I. -I.. -Isrc -I../src -fdiagnostics-color=always -fsanitize=address,undefined -fno-omit-frame-pointer -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c99 -O0 -g -D_POSIX_C_SOURCE=200809L -Wno-unused-parameter -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden -fPIC -pthread -MD -MQ tests/libtest-runner.a.p/test-compositor.c.o -MF tests/libtest-runner.a.p/test-compositor.c.o.d -o tests/libtest-runner.a.p/test-compositor.c.o -c ../tests/test-compositor.c ../tests/test-compositor.c: In function 'get_socket_name': ../tests/test-compositor.c:95:60: error: format '%ld' expects argument of type 'long int', but argument 5 has type '__time64_t' {aka 'long long int'} [-Werror=format=] 95 | snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld", | ~~^ | | | long int | %lld 96 | getpid(), tv.tv_sec, tv.tv_usec); | ~~~~~~~~~ | | | __time64_t {aka long long int} ../tests/test-compositor.c:95:63: error: format '%ld' expects argument of type 'long int', but argument 6 has type '__suseconds64_t' {aka 'long long int'} [-Werror=format=] 95 | snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld", | ~~^ | | | long int | %lld 96 | getpid(), tv.tv_sec, tv.tv_usec); | ~~~~~~~~~~ | | | __suseconds64_t {aka long long int} Signed-off-by: Simon Ser --- tests/test-compositor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 8ec0631b..efec31fa 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -92,8 +92,8 @@ get_socket_name(void) static char retval[64]; gettimeofday(&tv, NULL); - snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld", - getpid(), tv.tv_sec, tv.tv_usec); + snprintf(retval, sizeof retval, "wayland-test-%d-%lld%lld", + (int) getpid(), (long long int) tv.tv_sec, (long long int) tv.tv_usec); return retval; } From 92229a00d16fc43c752a17f608ff930395eecc57 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 27 Dec 2025 12:14:39 +0100 Subject: [PATCH 1102/1152] ci: bump Debian to Trixie Signed-off-by: Simon Ser --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bde40e7f..2ad999a7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -77,11 +77,11 @@ workflow: .os-debian: variables: BUILD_OS: debian - FDO_DISTRIBUTION_VERSION: bookworm + FDO_DISTRIBUTION_VERSION: trixie FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson ninja-build' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2025-10-28.1" + FDO_DISTRIBUTION_TAG: "2025-12-27.0" .debian-x86_64: extends: From 5a45a89a83c78a2a1f817d71c6cf94830a89d31e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 6 Jan 2026 11:09:18 +0100 Subject: [PATCH 1103/1152] ci: install to prefix after building in Debian Artifacts include the prefix directory, but it was empty: we weren't running the install step. Run it to align Debian with FreeBSD. This allows reviewers to check the HTML documentation output. Signed-off-by: Simon Ser --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2ad999a7..39beeaf3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -225,6 +225,7 @@ armv7-debian-container_prep: - meson setup $BUILDDIR --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} - ninja -C $BUILDDIR -k0 -j${FDO_CI_CONCURRENT:-4} - meson test -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4} + - ninja -C $BUILDDIR install - ninja -C $BUILDDIR clean artifacts: name: wayland-$CI_JOB_NAME From 0e0c0d5016f27edeaf1e709df52e47003d43acb3 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 16 Jan 2026 14:42:16 +0200 Subject: [PATCH 1104/1152] doc: remove Preface.xml This was never filled out, so might as well just delete it. Signed-off-by: Pekka Paalanen --- doc/publican/Preface.xml | 20 -------------------- doc/publican/Wayland.xml | 1 - doc/publican/meson.build | 1 - 3 files changed, 22 deletions(-) delete mode 100644 doc/publican/Preface.xml diff --git a/doc/publican/Preface.xml b/doc/publican/Preface.xml deleted file mode 100644 index 17c6ebff..00000000 --- a/doc/publican/Preface.xml +++ /dev/null @@ -1,20 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - - Acknowledgments - - - TODO: Kristian has to fill up this with one or two paragraphs and a small - "thank you": http://en.wikipedia.org/wiki/Preface - - -Best, - - Kristian Høgsberg - - diff --git a/doc/publican/Wayland.xml b/doc/publican/Wayland.xml index 7593097e..852c2971 100644 --- a/doc/publican/Wayland.xml +++ b/doc/publican/Wayland.xml @@ -6,7 +6,6 @@ - diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 6be7bad3..d70ea628 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -12,7 +12,6 @@ foreach src : files([ 'Book_Info.xml', 'Author_Group.xml', 'Foreword.xml', - 'Preface.xml', 'Revision_History.xml', 'Protocol.xml', 'Xwayland.xml', From ad1692d111c3d5f7ca237383ea3a9a58dcf7081e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 16 Jan 2026 14:44:33 +0200 Subject: [PATCH 1105/1152] doc: remove Revision_History.xml This was never used. Signed-off-by: Pekka Paalanen --- doc/publican/Revision_History.xml | 7 ------- doc/publican/meson.build | 1 - 2 files changed, 8 deletions(-) delete mode 100644 doc/publican/Revision_History.xml diff --git a/doc/publican/Revision_History.xml b/doc/publican/Revision_History.xml deleted file mode 100644 index 2c540fec..00000000 --- a/doc/publican/Revision_History.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - 1-0 - krh - Initial version - - diff --git a/doc/publican/meson.build b/doc/publican/meson.build index d70ea628..2edf7988 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -12,7 +12,6 @@ foreach src : files([ 'Book_Info.xml', 'Author_Group.xml', 'Foreword.xml', - 'Revision_History.xml', 'Protocol.xml', 'Xwayland.xml', 'Compositors.xml', From 924d79097b704cea7df247daed3a24b81e481bc9 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 20 Jan 2026 16:40:56 +0200 Subject: [PATCH 1106/1152] doc: remove unused CSS files I could not find them referenced anywhere. Signed-off-by: Pekka Paalanen --- doc/publican/html/css/brand.css | 14 ---- doc/publican/html/css/epub.css | 115 ------------------------------ doc/publican/html/css/meson.build | 3 - doc/publican/html/css/print.css | 15 ---- 4 files changed, 147 deletions(-) delete mode 100644 doc/publican/html/css/brand.css delete mode 100644 doc/publican/html/css/epub.css delete mode 100644 doc/publican/html/css/print.css diff --git a/doc/publican/html/css/brand.css b/doc/publican/html/css/brand.css deleted file mode 100644 index d86cba93..00000000 --- a/doc/publican/html/css/brand.css +++ /dev/null @@ -1,14 +0,0 @@ -/*headings*/ -h1, h2, h3, h4, h5, h6, -div.producttitle, -div.subtitle, -div.author div.author, -div.translator div.translator, -div.othercredit div.othercredit, -div.editor div.editor, -div.contrib div.contrib, -.title, -.titlepage .edition, -.titlepage .releaseinfo { - color: #336699; -} diff --git a/doc/publican/html/css/epub.css b/doc/publican/html/css/epub.css deleted file mode 100644 index b0ffd43c..00000000 --- a/doc/publican/html/css/epub.css +++ /dev/null @@ -1,115 +0,0 @@ -/*headings*/ -h1, h2, h3, h4, h5, h6, -div.producttitle, -div.subtitle, -div.author div.author, -div.translator div.translator, -div.othercredit div.othercredit, -div.editor div.editor, -div.contrib div.contrib, -.title, -.titlepage .edition { -} - -div.para { - margin-top: 1em; -} -/* inline syntax highlighting */ -.perl_Alert { - color: #0000ff; -} - -.perl_BaseN { - color: #007f00; -} - -.perl_BString { - color: #5C3566; -} - -.perl_Char { - color: #ff00ff; -} - -.perl_Comment { - color: #888888; -} - - -.perl_DataType { - color: #0000ff; -} - - -.perl_DecVal { - color: #00007f; -} - - -.perl_Error { - color: #ff0000; -} - - -.perl_Float { - color: #00007f; -} - - -.perl_Function { - color: #007f00; -} - - -.perl_IString { - color: #5C3566; -} - - -.perl_Keyword { - color: #002F5D; -} - - -.perl_Operator { - color: #ffa500; -} - - -.perl_Others { - color: #b03060; -} - - -.perl_RegionMarker { - color: #96b9ff; -} - - -.perl_Reserved { - color: #9b30ff; -} - - -.perl_String { - color: #5C3566; -} - - -.perl_Variable { - color: #0000ff; -} - - -.perl_Warning { - color: #0000ff; -} - -b, strong { - font-weight: bolder; -} - -code.command { - font-family: monospace; - font-weight: bolder; -} diff --git a/doc/publican/html/css/meson.build b/doc/publican/html/css/meson.build index 699d70ef..ddfbfe27 100644 --- a/doc/publican/html/css/meson.build +++ b/doc/publican/html/css/meson.build @@ -1,9 +1,6 @@ foreach src : files([ - 'brand.css', 'common.css', 'default.css', - 'epub.css', - 'print.css', ]) name = fs.name(src) publican_inputs += fs.copyfile( diff --git a/doc/publican/html/css/print.css b/doc/publican/html/css/print.css deleted file mode 100644 index 54088f48..00000000 --- a/doc/publican/html/css/print.css +++ /dev/null @@ -1,15 +0,0 @@ -@import url("common.css"); -@import url("overrides.css"); -@import url("lang.css"); - -#tocframe { - display: none; -} - -body.toc_embeded { - margin-left: 30px; -} - -.producttitle { - color: #336699; -} From fc331626733c091e6f0e89dc4c26c0bb7a810bb0 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 20 Jan 2026 17:16:45 +0200 Subject: [PATCH 1107/1152] doc: drop non-existing refs from CSS It seems these images were never in the repository. They might have existed when the documentation was still built with Publican, but since the migration to xmlto I think these have all been just 404. Removing div.warning:before, div.note:before and div.important:before would actually delete some unexpected empty space if the Docbook , or elements were used. They are not used now, but may be in the future. .draft is never used, so I replaced the image with whatever. Signed-off-by: Pekka Paalanen --- doc/publican/html/css/common.css | 35 ++++---------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/doc/publican/html/css/common.css b/doc/publican/html/css/common.css index a05648ef..d9c53e8f 100644 --- a/doc/publican/html/css/common.css +++ b/doc/publican/html/css/common.css @@ -204,7 +204,6 @@ div.producttitle { margin-bottom: 20px; font-size: 48px; font-weight: bold; -/* background: #003d6e url(../images/h1-bg.png) top left repeat-x; */ color: #336699; text-align: center; padding-top: 12px; @@ -642,13 +641,11 @@ div.authorgroup.contrib { /*Lists*/ ul { - list-style-image: url("../images/dot.png"); list-style-type: circle; padding-left: 1.6em; } ul ul { - list-style-image: url("../images/dot2.png"); list-style-type: circle; } @@ -882,21 +879,6 @@ code.email { } /*Notifications*/ -div.warning:before { - content:url(../images/warning.png); - padding-left: 5px; -} - -div.note:before { - content:url(../images/note.png); - padding-left: 5px; -} - -div.important:before { - content:url(../images/important.png); - padding-left: 5px; -} - div.warning, div.note, div.important { color: black; margin: 0px; @@ -932,21 +914,18 @@ div.admonition_header { } div.warning div.admonition_header { - background: url(../images/red.png) top left repeat-x; background-color: #590000; background: -webkit-linear-gradient(#a40000,#590000); background: linear-gradient(#a40000,#590000); } div.note div.admonition_header { - background: url(../images/green.png) top right repeat-x; background-color: #597800; background: -webkit-linear-gradient(#769f00,#597800); background: linear-gradient(#769f00,#597800); } div.important div.admonition_header { - background: url(../images/yellow.png) top right repeat-x; background-color: #a6710f; background: -webkit-linear-gradient(#d08e13,#a6710f); background: linear-gradient(#d08e13,#a6710f); @@ -1436,14 +1415,12 @@ ul li p:last-child, ul li para:last-child { } .docnav li.next a strong { - background: url(../images/stock-go-forward.png) right 120% no-repeat; padding-top:3px; padding-bottom:4px; padding-right:28px; } .docnav li.previous a strong { - background: url(../images/stock-go-back.png) left 120% no-repeat; padding-top:3px; padding-bottom:4px; padding-left:28px; @@ -1451,13 +1428,11 @@ ul li p:last-child, ul li para:last-child { } .docnav li.home a strong { - background: url(../images/stock-home.png) top left no-repeat; padding:5px; padding-left:28px; } .docnav li.up a strong { - background: url(../images/stock-go-up.png) top left no-repeat; padding:5px; padding-left:28px; } @@ -1538,7 +1513,6 @@ ul.docnav { display:inline; float:right; width:16em; - background:#c00 url(../images/shine.png) top left repeat-x; margin:0px; margin-top:-1.3em; padding:0px; @@ -1556,7 +1530,6 @@ div.progress { display:block; float:left; width:16em; - background:#c00 url(../images/shine.png) top left repeat-x; height:1em; } @@ -1566,11 +1539,11 @@ div.progress span { } div.progress span.translated { - background:#6c3 url(../images/shine.png) top left repeat-x; + background:#6c3; } div.progress span.fuzzy { - background:#ff9f00 url(../images/shine.png) top left repeat-x; + background:#ff9f00; } @@ -1626,7 +1599,7 @@ div.progress span.fuzzy { display:inline; float:right; width:16em; - background:#c00 url(../images/shine.png) top left repeat-x; + background:#c00; margin:0px; margin-top:-1.3em; padding:0px; @@ -1674,7 +1647,7 @@ span.remark { } .draft { - background-image: url(../images/watermark-draft.png); + background-color: #aaa; background-repeat: repeat-y; background-position: center; } From dd8afabdcc98f96408e42b443be06951b4a06f92 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 28 May 2024 21:04:35 +0200 Subject: [PATCH 1108/1152] protocol: Define Content Update behavior The protocol currently is in a state where we define that commits create content updates and they are queued up until they are applied, and the old view that commit applies the state or caches it in the parent state. This commit moves the protocol completely to the new model which retains the old behavior when no constraints are being used but allows for constraints to be used to hold back a group of synchronized content updates. To convince yourself that this indeed retains the original behavior I suggest to play around with a few examples and look at the resulting graphs, as is done here: https://gitlab.freedesktop.org/wayland/wayland/-/issues/457#note_2403135 Signed-off-by: Sebastian Wick --- protocol/wayland.xml | 133 +++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 69 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 5a6a189d..de6756b4 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -1687,21 +1687,48 @@ etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. - A commit request atomically creates a content update from the pending - state, even if the pending state has not been touched. The content - update is placed in a queue until it becomes active. After commit, the - new pending state is as documented for each related request. - - When the content update is applied, the wl_buffer is applied before all - other state. This means that all coordinates in double-buffered state - are relative to the newly attached wl_buffers, except for - wl_surface.attach itself. If there is no newly attached wl_buffer, the - coordinates are relative to the previous content update. - All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. + + A commit request atomically creates a Content Update (CU) from the + pending state, even if the pending state has not been touched. The + content update is placed at the end of a per-surface queue until it + becomes active. After commit, the new pending state is as documented for + each related request. + + A CU is either a Desync Content Update (DCU) or a Sync Content Update + (SCU). If the surface is effectively synchronized at the commit request, + it is a SCU, otherwise a DCU. + + When a surface transitions from effectively synchronized to effectively + desynchronized, all SCUs in its queue which are not reachable by any + DCU become DCUs and dependency edges from outside the queue to these CUs + are removed. + + See wl_subsurface for the definition of 'effectively synchronized' and + 'effectively desynchronized'. + + When a CU is placed in the queue, the CU has a dependency on the CU in + front of it and to the SCU at end of the queue of every direct child + surface if that SCU exists and does not have another dependent. This can + form a directed acyclic graph of CUs with dependencies as edges. + + In addition to surface state, the CU can have constraints that must be + satisfied before it can be applied. Other interfaces may add CU + constraints. + + All DCUs which do not have a SCU in front of themselves in their queue, + are candidates. If the graph that's reachable by a candidate does not + have any unsatisfied constraints, the entire graph must be applied + atomically. + + When a CU is applied, the wl_buffer is applied before all other state. + This means that all coordinates in double-buffered state are relative to + the newly attached wl_buffers, except for wl_surface.attach itself. If + there is no newly attached wl_buffer, the coordinates are relative to + the previous content update. @@ -3140,23 +3167,9 @@ hidden, or if a NULL wl_buffer is applied. These rules apply recursively through the tree of surfaces. - The behaviour of a wl_surface.commit request on a sub-surface - depends on the sub-surface's mode. The possible modes are - synchronized and desynchronized, see methods - wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized - mode caches the wl_surface state to be applied when the parent's - state gets applied, and desynchronized mode applies the pending - wl_surface state directly. A sub-surface is initially in the - synchronized mode. - - Sub-surfaces also have another kind of state, which is managed by - wl_subsurface requests, as opposed to wl_surface requests. This - state includes the sub-surface position relative to the parent - surface (wl_subsurface.set_position), and the stacking order of - the parent and its sub-surfaces (wl_subsurface.place_above and - .place_below). This state is applied when the parent surface's - wl_surface state is applied, regardless of the sub-surface's mode. - As the exception, set_sync and set_desync are effective immediately. + A sub-surface can be in one of two modes. The possible modes are + synchronized and desynchronized, see methods wl_subsurface.set_sync and + wl_subsurface.set_desync. The main surface can be thought to be always in desynchronized mode, since it does not have a parent in the sub-surfaces sense. @@ -3168,6 +3181,15 @@ synchronized mode, and then assume that all its child and grand-child sub-surfaces are synchronized, too, without explicitly setting them. + If a surface behaves as in synchronized mode, it is effectively + synchronized, otherwise it is effectively desynchronized. + + A sub-surface is initially in the synchronized mode. + + The wl_subsurface interface has requests which modify double-buffered + state of the parent surface (wl_subsurface.set_position, .place_above and + .place_below). + Destroying a sub-surface takes effect immediately. If you need to synchronize the removal of a sub-surface to the parent surface update, unmap the sub-surface first by attaching a NULL wl_buffer, update parent, @@ -3198,20 +3220,18 @@ - This schedules a sub-surface position change. + This sets the position of the sub-surface, relative to the parent + surface. + The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. - The scheduled coordinates will take effect whenever the state of the - parent surface is applied. - - If more than one set_position request is invoked by the client before - the commit of the parent surface, the position of a new request always - replaces the scheduled position from any previous request. - The initial position is 0, 0. + + Position is double-buffered state on the parent surface, see + wl_subsurface and wl_surface.commit for more information. @@ -3225,13 +3245,11 @@ parent surface. Using any other surface, including this sub-surface, will cause a protocol error. - The z-order is double-buffered. Requests are handled in order and - applied immediately to a pending state. The final pending state is - copied to the active state the next time the state of the parent - surface is applied. - A new sub-surface is initially added as the top-most in the stack of its siblings and parent. + + Z-order is double-buffered state on the parent surface, see + wl_subsurface and wl_surface.commit for more information. @@ -3240,6 +3258,7 @@ The sub-surface is placed just below the reference surface. + See wl_subsurface.place_above. Change the commit behaviour of the sub-surface to synchronized - mode, also described as the parent dependent mode. + mode. - In synchronized mode, wl_surface.commit on a sub-surface will - accumulate the committed state in a cache, but the state will - not be applied and hence will not change the compositor output. - The cached state is applied to the sub-surface immediately after - the parent surface's state is applied. This ensures atomic - updates of the parent and all its synchronized sub-surfaces. - Applying the cached state will invalidate the cache, so further - parent surface commits do not (re-)apply old state. - - See wl_subsurface for the recursive effect of this mode. + See wl_subsurface and wl_surface.commit for more information. Change the commit behaviour of the sub-surface to desynchronized - mode, also described as independent or freely running mode. + mode. - In desynchronized mode, wl_surface.commit on a sub-surface will - apply the pending state directly, without caching, as happens - normally with a wl_surface. Calling wl_surface.commit on the - parent surface has no effect on the sub-surface's wl_surface - state. This mode allows a sub-surface to be updated on its own. - - If cached state exists when wl_surface.commit is called in - desynchronized mode, the pending state is added to the cached - state, and applied as a whole. This invalidates the cache. - - Note: even if a sub-surface is set to desynchronized, a parent - sub-surface may override it to behave as synchronized. For details, - see wl_subsurface. - - If a surface's parent surface behaves as desynchronized, then - the cached state is applied on set_desync. + See wl_subsurface and wl_surface.commit for more information. From 1807450a7ba8cc8c8449850d5fed09b2b2e2d234 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 28 Oct 2025 11:54:12 +0100 Subject: [PATCH 1109/1152] doc: Add a chapter on content updates The behavior of content updates, specifically in combination with sync subsrufaces and constrains can become quite complicated. This introduces a chapter in the wayland book which explains the behavior of the core specification in this regard, and shows examples. Signed-off-by: Sebastian Wick --- doc/publican/Content_Updates.xml | 460 +++++ doc/publican/Wayland.xml | 1 + .../content-updates/content-update-legend.png | Bin 0 -> 15946 bytes .../content-updates/content-updates.drawio | 1528 +++++++++++++++++ .../html/images/content-updates/meson.build | 35 + .../simple-desynchronized-state-1.png | Bin 0 -> 2037 bytes .../simple-desynchronized-state-2.png | Bin 0 -> 6732 bytes .../simple-desynchronized-state-3.png | Bin 0 -> 1625 bytes .../simple-desynchronized-state-4.png | Bin 0 -> 7302 bytes .../simple-desynchronized-state-5.png | Bin 0 -> 12728 bytes .../simple-desynchronized-state-6.png | Bin 0 -> 2102 bytes .../simple-desynchronized.drawio | 198 +++ .../simple-synchronized-state-1.png | Bin 0 -> 2117 bytes .../simple-synchronized-state-2.png | Bin 0 -> 2586 bytes .../simple-synchronized-state-3.png | Bin 0 -> 2989 bytes .../simple-synchronized-state-4.png | Bin 0 -> 17710 bytes .../simple-synchronized-state-5.png | Bin 0 -> 2209 bytes .../simple-synchronized.drawio | 207 +++ .../content-updates/sync-subsurf-case1-1.png | Bin 0 -> 26995 bytes .../content-updates/sync-subsurf-case1-2.png | Bin 0 -> 27535 bytes .../content-updates/sync-subsurf-case1-3.png | Bin 0 -> 22771 bytes .../content-updates/sync-subsurf-case1-4.png | Bin 0 -> 22017 bytes .../content-updates/sync-subsurf-case1-5.png | Bin 0 -> 10932 bytes .../content-updates/sync-subsurf-case1.drawio | 500 ++++++ .../content-updates/sync-subsurf-case2-1.png | Bin 0 -> 26210 bytes .../content-updates/sync-subsurf-case2-2.png | Bin 0 -> 25821 bytes .../content-updates/sync-subsurf-case2-3.png | Bin 0 -> 10069 bytes .../content-updates/sync-subsurf-case2.drawio | 287 ++++ .../sync-to-desync-subsurf-1.png | Bin 0 -> 18621 bytes .../sync-to-desync-subsurf-2.png | Bin 0 -> 18069 bytes .../sync-to-desync-subsurf-3.png | Bin 0 -> 19371 bytes .../sync-to-desync-subsurf.drawio | 223 +++ .../sync-to-desync-transition-1.png | Bin 0 -> 9299 bytes .../sync-to-desync-transition-2.png | Bin 0 -> 15177 bytes .../sync-to-desync-transition-3.png | Bin 0 -> 15872 bytes .../sync-to-desync-transition.drawio | 203 +++ doc/publican/html/images/meson.build | 2 + doc/publican/meson.build | 1 + 38 files changed, 3645 insertions(+) create mode 100644 doc/publican/Content_Updates.xml create mode 100644 doc/publican/html/images/content-updates/content-update-legend.png create mode 100644 doc/publican/html/images/content-updates/content-updates.drawio create mode 100644 doc/publican/html/images/content-updates/meson.build create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-1.png create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-2.png create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-3.png create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-4.png create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-5.png create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-6.png create mode 100644 doc/publican/html/images/content-updates/simple-desynchronized.drawio create mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-1.png create mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-2.png create mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-3.png create mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-4.png create mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-5.png create mode 100644 doc/publican/html/images/content-updates/simple-synchronized.drawio create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-1.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-2.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-3.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-4.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-5.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1.drawio create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2-1.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2-2.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2-3.png create mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2.drawio create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf-1.png create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf-2.png create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf-3.png create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition-1.png create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition-2.png create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition-3.png create mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition.drawio diff --git a/doc/publican/Content_Updates.xml b/doc/publican/Content_Updates.xml new file mode 100644 index 00000000..30c4ed33 --- /dev/null +++ b/doc/publican/Content_Updates.xml @@ -0,0 +1,460 @@ + + +%BOOK_ENTITIES; +]> + + + Content Updates + +
+ Overview + + + In the Wayland protocol, requests are asynchronous but take effect + immediately when the compositor receives them. However, some requests on + surfaces are not applied immediately but are instead double-buffered to + allow atomic changes. These double-buffered changes are committed through + the wl_surface.commit request, which creates a Content Update. + + + + Content Updates encapsulate all double-buffered state changes and can be + applied by the compositor. The complexity arises when considering + subsurfaces, which can operate in synchronized mode. When a subsurface is + synchronized, its Content Updates must be applied atomically together with + the parent surface's state. This synchronization can extend through an + entire tree of subsurfaces, where child subsurfaces inherit the + synchronized behavior from their parents. + + + + Historically, Content Updates from synchronized subsurfaces were merged + into the pending state of the parent surface on commit. However, the + introduction of constraints—which can defer the application of Content + Updates—necessitated a more sophisticated model. This led to the + implementation of per-surface queues of Content Updates, with dependencies + between Content Updates across different queues. This queuing model + maintains backwards compatibility with the earlier approach of merging + Content Updates into the parent's pending state on commit. + + + + The core protocol defines the semantics of Content Updates using + per-surface queues, but compositors that do not need to support constraints + may implement the simpler legacy model where synchronized subsurface states + are merged directly into the parent's pending state. + +
+ +
+ Rules + + + The core protocol specifies the behavior in wl_subsurface and + wl_surface.commit. The behavior can be summarized by the following rules: + + + + + + Content Updates (CU) contain all double-buffered state of the surface and + selected state from their direct children. + + + + + Surfaces which are effectively synchronized create Synchronized + Content Updates (SCU), otherwise they create Desync Content Updates + (DCU). + + + + + When a CU is created, it gets a dependency on the previous CU of the + same queues (if it exists). + + + + + When a CU is created, it gets a dependency on the last SCU of direct + child surfaces that are not reachable (if they exists). + + + + + The CUs and their dependencies form a DAG, where CUs are nodes and + dependencies are edges. + + + + + All DCUs starting from the front of the queues until the first SCU or + the back of the queue is reached are candidates. + + + + + If the maximal DAG that's reachable from a candidate (candidate DAG) + does not have any constraints, then this DAG can be applied. + + + + + A DAG is applied atomically by recursively applying a content update + without dependencies and removing it from the DAG. + + + + + Surfaces transition from effectively sync to effectively desync after + their parents. + + + + + When a surface transitions to effectively desync, all SCUs in its + queue which are not reachable by a DCU become DCUs. + + + +
+ +
+ Examples + + + These examples should help to build an intuition for how content updates + actually behave. They cover the interesting edge cases, such as + subsurfaces with constraints, and transitioning from a sync subsurface to + a desync one. + + + In all the examples below, the surface T1 refers to a toplevel surface, + SS1 refers to a sub-surface which is a child of T1, and SS2 refers to a + sub-surface which is a child of SS1. + + +
+ Legend + + + + + +
+ +
+ Simple Desynchronized Case + + + + + + + SS2 is effectively desynchronized and commits. This results in the + desynchronized content update (DCU) 1. + + + + + + + + + + DCU 1 is a candidate, and the candidate DAG + reachable from DCU 1 is only + DCU 1 itself. DCU 1 and + thus the candidate DAG does not have any constraints and can be + applied. + + + + + + + + + + The content updates of the candidate DAG get applied to the surface + atomically. + + + + + + + + + + T1 commits a DCU with a buffer-sync constraint. + It is a candidate but its DAG can't be applied because it contains a + constraint. + + + + + + + + + + T1 commits another CU (DCU 3) which is added at + the end of the queue, with a dependency to the previous CU (DCU + 2). Both DCU 2 and DCU + 3 are candidates, but both DAGs contain DCU + 2 with a constraint, and can't be applied. + + + + + + + + + + When the constraint gets cleared, both DAGs can be applied to the + surface atomitcally (either only 2, or + 2 and 3). + + + +
+ +
+ Simple Synchronized Case + + + + + + + SS1 and SS2 are effectively synchronized. SS2 commits SCU 1. + + + + + + + + + + SS1 commits SCU 2. The direct child surfaces SS2 has the last SCU 1 in its queue, which is not reachable. This creates a dependency from SCU 2 to SCU 1. + + + + + + + + + + SS1 commits SCU 3. The direct child surfaces SS2 has the last SCU 1 in its queue, which is already reachable by SCU 2. No dependency to SCU 1 is created. A dependency to the previous CU of the same queue (SCU 2) is created. + + + + + + + + + + T1 commit DCU 4. It is a candidate, its DAG does not contain any constraint and it can be applied. + + + + + + + + + + The DAG gets applied to the surfaces atomically. + + + +
+ +
+ Complex Synchronized Subsurface Case 1 + + + + + + + Every DCU (1 and 6) contain + CUs with constraints in their candidate DAG + + + + + + + + + + Waiting until the buffer-sync constrain on CU + 1 is cleared, the candidate DAG of CU + 1 does not contain constraints and can be applied + + + + + + + + + + That leaves the candidate DAG of CU 6 which still + contains another CU with a buffer-sync constrain + + + + + + + + + + Waiting until the buffer-sync constrain on CU + 6 is cleared, the candidate DAG of + 6 does not contain CUs with constraints and can + be applied. + + + + + + + + + + There is no DCU left and no constraint remaining. Nothing more can be + applied without a new CU. + + + +
+ +
+ Complex Synchronized Subsurface Case 2 + + + + + + + Both DCUs (1 and 6) have a + reachable DAG containing CU 1 with a constraint + + + + + + + + + + Waiting until the buffer-sync constrain on + 1 is cleared, both DAGs contain no CU with + constraints and can be applied in any order + + + + + + + + + + That leaves the same state as in the previous case + + + +
+ +
+ Synchronized to Desynchronized Subsurface + + + + + + + There is one DCU (4) with its reachable DAG + that cannot be applied because CU 4 contains a + constraint + + + + + + + + + + Surface SS1 transitions from effectively + synchronized to effectively desynchronized. SCU + 2 is reachable by DCU 4 so + nothing changes. + + + + + + + + + + Surface SS1 provides a new DCU + (5) but because the CU before + (2) is a Synchronized CU, it is not a candidate + + + +
+ +
+ Synchronized to Desynchronized Transition + + + + + + + There are four SCUs and all surfaces are effectively synchronized. + + + + + + + + + + Surface SS1 transitions to effectively + desynchronized and SCU 2 becomes a DCU because + it is not reachable from a DCU + + + + + + + + + + Surface SS2 transitions to effectively + desynchronized. SCUs 3 and + 4 become DCUs because they are not reachable + from a DCU. SCU 1 does not change because it is + reachable by DCU 2. + + + +
+ +
+
diff --git a/doc/publican/Wayland.xml b/doc/publican/Wayland.xml index 852c2971..f02a97fc 100644 --- a/doc/publican/Wayland.xml +++ b/doc/publican/Wayland.xml @@ -11,6 +11,7 @@ + diff --git a/doc/publican/html/images/content-updates/content-update-legend.png b/doc/publican/html/images/content-updates/content-update-legend.png new file mode 100644 index 0000000000000000000000000000000000000000..84f12e76aefa65bdc7fe98fb81bc168fdbb14416 GIT binary patch literal 15946 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
L23 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/content-updates/meson.build b/doc/publican/html/images/content-updates/meson.build new file mode 100644 index 00000000..850e81ff --- /dev/null +++ b/doc/publican/html/images/content-updates/meson.build @@ -0,0 +1,35 @@ +foreach src : files([ + 'simple-desynchronized-state-1.png', + 'simple-desynchronized-state-2.png', + 'simple-desynchronized-state-3.png', + 'simple-desynchronized-state-4.png', + 'simple-desynchronized-state-5.png', + 'simple-desynchronized-state-6.png', + 'simple-synchronized-state-1.png', + 'simple-synchronized-state-2.png', + 'simple-synchronized-state-3.png', + 'simple-synchronized-state-4.png', + 'simple-synchronized-state-5.png', + 'sync-subsurf-case1-1.png', + 'sync-subsurf-case1-2.png', + 'sync-subsurf-case1-3.png', + 'sync-subsurf-case1-4.png', + 'sync-subsurf-case1-5.png', + 'sync-subsurf-case2-1.png', + 'sync-subsurf-case2-2.png', + 'sync-subsurf-case2-3.png', + 'sync-to-desync-subsurf-1.png', + 'sync-to-desync-subsurf-2.png', + 'sync-to-desync-subsurf-3.png', + 'sync-to-desync-transition-1.png', + 'sync-to-desync-transition-2.png', + 'sync-to-desync-transition-3.png', + 'content-update-legend.png', +]) + name = fs.name(src) + publican_inputs += fs.copyfile( + name, + install: true, + install_dir: publican_install_prefix + '/html/images/content-updates', + ) +endforeach diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-1.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d319ac2579f10e583afc13d6dd3bd467dc769ef1 GIT binary patch literal 2037 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMnSp_Ub;foOrI73q~wMMX|k)80QKB(pTCu)dZHZ?Wn<>j@sw466@Uhl?Z+lzNb!|VqsyCl9I~J&5enPdH??XrcIkTIXT(b*cL2U(7JrLp{?uUGfx^8Z1(o{ zK6&!wuV24{f`ZN#C@6U3$Po(*i?Fb;moHyVnKC6JB4Ypk{rdX)*4EZ)YHAlRUi9+v5)l!R zmX?;0kufwhESa=;)BRstwrttEckj%ZGnX!1`r^fl*RNkMTC}LCsYyaY!o$O(t*veG z;>Eqay&E=c2nYyhZf;()W=%^=OH@=8D=RB+z<*H&1_s6?Z+91l4pvzY1_lQ95>H=O z_E(GooCY$Np6rcaU|@OS>EaktaqI2fpTWZE5(hrEJ3J7~n9#s-;aV802+ucxa8Ab; ztsmb!y~riFH1x=7*V|oDuB#VqZMS_<`)~PN-i2w+rEF=_pPa0*-`}wNy+Pi-b(P<_ zlo(Kf+0@ok+J{7+F5Kkw-*tmZ>eNuH^{XazHAa6->Hb%F)pYBu)n+lVFMM@MwdYk$ za#ioSlDTh}$HMI!kNljyL1}hwYV8)qsQpI2mv=ekr(}LMO-x>PV^!O-8*`RD3!SOj z+j{TRq-W`ecGeo)5~^OJda6#sL|)kKPQ=>P$#JWr?;hPF&vtx&%hh*2%SwH9?n`Y? zl>L0^z>n!0j@`Ze?EAsx^8;h8_sj3nKGb^e!lkFthm5{g7|dGx?M?A7jl?sx_G_L> z)N5W_d;h|ta%kci#Me6(8nCoSD4gWbDcROS-QwW#``+ z&!7FrBdhM=?qBoLC&Y6)zq6b&(nM34V8K06ppw4+D8!A5A7yVGZnh%2ZGV)v75+4IuQhmy91R&TT16*4sBXSO0eTX3eg$j*rv#<)!BKJL}s`>r|fBeg1I!y+_6=P1?|oc@+hTe785kH;OI#yLQW8s2t&)pU6H8JVj0}v-bPWu34NXIg z46RH|txPPn4GgRd4D?sI>_E|wo1c=IR*9y;$kNKd5TZf)_OuWN1_lkd4JDbmsl_FU jxdjM4W+4WaRwfo!Mivk~d<(y4ft=~->gTe~DWM4f`Yf6v literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-2.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd284cd6751882532c29984c00957ebdf323b8e GIT binary patch literal 6732 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 b%EZFT$O58=Z{hbWkRv@^{an^LB{Ts5an#hk literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-4.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-4.png new file mode 100644 index 0000000000000000000000000000000000000000..83dcc063fac852fc513e3bfeb63a7450462cb454 GIT binary patch literal 7302 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 P1_lOCS3j3^P6&6h2cL4F4((#G6Mqxdx@v7 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 aurjiM=;2%VJ&S>Xfx*+&&t;ucLK6Tuv==A< literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-6.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-6.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb88d8189e24c11c018540d8068380b753031df GIT binary patch literal 2102 zcmeAS@N?(olHy`uVBq!ia0y~yU_8vg!0?-cnSp^pk&S-_0|SFXvPY0F14ES>14Ba# z1H&%{28M(N=nM^ zmDAW*Sq-$+LPJAOoH#LO&Ybn@*JoyC*4EZ8p4_y3>7?HJ!t2+si;Ih=r>DPt`}Xta z&%wdLJUl#petuW3Tv@SV1rrm~^XJbeO`0SrDXFWg`|;z)fB*h1U%oseBSTwTo1dTm z+_`fL7cRVf`SSPg-y0hn6A}`pPoJ)*r+5GUeH|Sg6&022?Cd2=mIw+89yxNv!ouRq zmoH&qVb0FZFJHc#GG$6cM8y96`}Otp@1NYXf6dIC#IRZ2)juB|x3;!cQ&YQm@#5yq zo4vfeL_|cSrKM$LWDE@rn@TgDU)Z^2%a*-+_s*O-bLrBhFJ8QO{rdHyMT?r6nkp(P zBqSs}JUrUk+7>Tf+}qo`aY3J{ftCOtZ?L!1onsr$?_TEaVCi6Ge0am04I4HD1O!~# zyTZ&+J1;qcmxs&TNay3tgJL2=s)}-jX;F%DQhdDJ@2>A_Zf;()X3eq9^PZmH9_Huz z`_ajZdzMdVDn7bto|L$#y0ZM;;~QOU&E#byUtZd!ucfwi@x&!lnuP`VAD`VODK7Hj z;;u~#`y%|^_<4D*>|gcc!7*b!%`-a|A6z$Ua%)*jOG{K#)WqfzPbaIHT~#}lO}=q> zEei{CWp1Lax#7vJ3t3rN^HU;st(eNi$-&CPVri_maz?wGy~XuIYg80ue?2_0eANMA z1_lPkByV>Yh7ML)4+aJX_7YEDSN2zo0-Odim!9m6U|?Wr@pN$vskrs_?$7X$REYy0 z(~kv4ili9G?>S|_p=+`3tzPb-4ld0{VHrz1mM-#K+Vm`8+l6_qzms-vi?}gQciZ&0 zzrQ^%NnI?Qs$CgSLBoH|3+?~**?rNqSP^bw zqF|wMgsvZRTDaZkJ&|6x z@U~m##SH)BCvH6Q@C;F2YUFqN(9^1-XFdBLYA%13X;R|Z+Bf|MOa3F3xjIHiXKO8g zEm^c|-c-xS*%jX`pI^G5`_n47>QixBTl%rSIX3?1&(Ha2y63^6?u-}HB3)Na4K17* zyVffG-JUBuXWcq+bf&TGyLOWj-*bOnFs+T&_}VR|e{tz)mnV}R?eVTvHYtgBZWUX? zH|;go#M56sY5#f6D78yxUr}hxlECnA^RoF*{Uug)Z5ed;8nAu!*ltGu@x{tWQ+h zde6@}nyJP=Sq?df?4)kFL&J@GL;A5j3*@V>qXsqxFM)yc%fkKZ`D?j9>12FvvYC9> z24M&^@cX1~QZmBI`aIrkcv$&Uc~W{=*4+A*wmj*ju8VDDm6N-bRRepcblth&;vB72 zvge3eg|Pa|l!==6LO55uJ4b&iz4hhEa~|IFJ*xa=cPoT>b7zJwiHa1Re)H<8;%Dc) z=k1!=cI?TSe!UC3T7&jyd=!e^)zfBX8j|7oDq-ikAM4xpcwfu>ICb?SrQTh;c4hW@ z^oCu$FmJ1rX5{jzuV-)7*|jjn{FJWj_E)*Gvb>VUCMD5pDvKXZdl5GA+P2)=x1(J1 zu1~qtBZ=XyZx=7X0xZ74*7zCg-y6HxFaiiwfZ1aK|KHl$7ts^a9cLfkor07;p=Q0< z_vQALuY7_huN|vjfB8b~yzS1~w(tE`?)R?FtoUxb`~BYc9y`zdF1P=nz$^P{f}M`i z(pC39O4|kfev#a7e{pWX`N{saf6r__fANCs%QoKg&)?bB9j@&ZchZ05{jzPgkbe8O z*V-l}?zl=SRXuKYG-`Tl*PQ+pJduwW6XB^u8b*|XEcD|Q;6Tk0H zx&PK`$NL-WA6CDw|L{;zYS&{Isk$#84>G%R*G;kz`4wWnc%k(!>AHI#Tl?PJxLRy_ z_k;Iet%)96RdP{kVo554k%5t!u7RPhp=pSbp_PfLm5HUc zfq|8Qf&MC&9Vi-d^HVa@D$z6;Sz4JILNo+h&oE$MV9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/content-updates/simple-synchronized-state-1.png b/doc/publican/html/images/content-updates/simple-synchronized-state-1.png new file mode 100644 index 0000000000000000000000000000000000000000..be101446104f7798a8d39f8edb0dbd1bdec3e24b GIT binary patch literal 2117 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 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/simple-synchronized-state-4.png b/doc/publican/html/images/content-updates/simple-synchronized-state-4.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b9b3db323541330fcfecce76c831f62c97698a GIT binary patch literal 17710 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 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/simple-synchronized.drawio b/doc/publican/html/images/content-updates/simple-synchronized.drawio new file mode 100644 index 00000000..a478ae02 --- /dev/null +++ b/doc/publican/html/images/content-updates/simple-synchronized.drawio @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-1.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7ff8e42b9783c3ee6fb54c66828ec033cdd13d GIT binary patch literal 26995 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 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-2.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-2.png new file mode 100644 index 0000000000000000000000000000000000000000..6839b679990902c4ae4a4a5e092244d74b853ee7 GIT binary patch literal 27535 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMiGhJ(ugZlq1_lO&WRD&6h2cL4F4((#G6Mqxdx@v7 zEBh-(0Zs#%OHcMjFfhcbd%8G=RNQ(yx3WgW_15v#)w`ab@Zl3G67WcCa0&Pr+FT*1 zG|4sa!wpt(7moI>MZb4-Uo>^hYjR=z=lI-B#Xm zW(^Upr+3;;X|y^mWMQ2e$kpn^$)&YegsW9ZB*aZqgiBRpM}c{R(@Q2Pvv$gK!#)_YN?Pc5VSH6*R4RmSeIBHYY|5U2` zV46bqha0wRvlSh-E)6hgJhful1poZyj5`mCXZZgMVQ1F7{PuL|dY|f}BCa2A*m5j< zR(qCX;f~0{h_5omvR`Mv4t-jwZU5$j!L(G#w#3M5JMTwYtrO`}Zqd0OA>i~($M_0! z$)C?|3rm=_7SCF!;q~=X)*Fq3j(bDrZ&BftOK6!;ynl05rRg8e>5d${f1d|@SS8U` z_^#aQnU%*vL0P5zr@?W)oifs$ryJrDPBMg~hJ0nnJepax`rh`QgJ}mu)pR`%#m##l zuxffZcUj|_BXd%Zl^OCp-dO$0>?$W;M4)zVfq$PaF80?UH(4 zx4d}&-FhLNvAuFmOex$A;8Srxh#`CU3#{7$cYwF&pD z=_;O+RAQdJ*~upu_aW@w>#vhiYhGvWo)*q7Clkqby;-2^bpPSEAE#8;d_BGMzNDq? zC5syzsjtkgUR|@|{+S1v@(A4B8?xFV%jdAlUxE>$~Dv6dg3)RZ(TleF2%C%^2-vfy%(0g*dcPx;?|1Y zG0#6%RLr~nvc%9hDJAk6@1@GUaT114f-HiUb*4t{5SwC{I%`kddY#jgR2)}-3EO)} zt4ZO&)?a7ew4bgxW&2=3;Yt~)2A4pV#4ZV8!zY&&*B*}&b^TbiH(|Qw3_)A#rnI4JLCfqxEGWd@des%r2FK>a)>3c5vFQzZjU^e3^cvoJvH?Bu2|FwN1Vue3r9?i{e_mMW8u%l` z?pI&NV|C5awOcn`-E-j0*Q$fodH1frv3d|RHIaSe+T&3(7xGv( z99UYEAnVj2d*W00C$C9Nws~!dk3K!-374Lc;wIvnzbM=@NW?WUGVEFE9qs2qJ5JnI zR`q0R6m}I<;n~7-Ut>pjLG*(ng@W9FYNub7SZOq;PYaP#b$0mI^+2!b`s>!PiLHnK zsxF#yI6(5M(4PaFb*jTkBBo`sPw?CCZ#4aoXI|&m4LM5PwrV`{PpR*np~Asbw)<8} zYx0!%M!&rZ98C%xi#Rr&+oWSX;b;)+++WuguPvIS)1`Ff@X`XE|Few(FE3_sEZBYb z$<`BnoA0gapC$M7V}(e+68EO?tjVP@ov;2SRDY~h;6HTt@FLFtlfSp8MoRcJ7|9%W zJT9L#AyqOa^T$es*MizE0@;6(ox?2_v+z$1JlhcY{vY>m_j_`j{Tedu=@NYnVhQ=& zRf|6yXcl;2RKUW*{jZ%#L2Stdhrb`ht}}dCX(Kf8QQ(9QiOz#^GAkpiR?G1^G%08_ zHK{z=&hsyq;ntHM+w&B{wEG@!ka}d6d|uF8^k2K#Ds{So~g z{NaFe<)ybxj-EDixGpW5^myC7FYEiHBipWc?a(_Ruji~~6v_XN`|+^{-yWDXAA4xD z<7~vQkNljG_IFG|zu4XM%VE8vx@N`>iAu43+kYt3o#tEQr{U_oq9=>l(uPaPX;E%$@-rWFHb}-zZ9^4#lKr|iJ#Pd`)V2UnQdZ@obgn>UQuI8!UCgJ zj7x4zH1hfuT`Paxuk~;^cgWWtyJDa0;jMdkd+*n|PdJzKWH}vs|07dD=;ief3{Tfw zPLdT-U{60eQ+w4Cko%-`Zg7THF5YqbUA33Od0oG?FC*%22kU)W>(y7gnsu)cuNZNk-OVL7}mR)B{rdj;lQm&6wst&%h}PV(74lf`jDYNY8}5gWbftCuWUvSrJbZQHKBEtBp& z*3#1Q<;$0z9-hsXR}RTCZP_Zmi*>>kes6&Z7k5A07Fu0hZC`sPPHXW&C%;+Fa|D(| zP1^Y7?y;vuqN1X?_xJ7Hv17+xqnkHxPFD9nck-mA`2Kpu&Eo4*PA&g5A>O}j(>L4d zYW3QyanI&-IRATkRqoFs{{7lFtQ$VRD6~^`nRhtL=dN(D=OivJu50UJUzb=hYvyl^ zC@L-%*Nr+-`22}~a{n!E`3cGE7B5_Ja7w1vt%)qc4Ida+8u|Wi*t>VazTEeg%8L)H z*IiXMeZR{`STc02$D&gKZ(arODt>;Bm0N7e)TyOgRWma)Ute20+axo{|IX@piN9O)v*H>37 zD=TdacULvd+a~`1#NR33Cch9+UgqXvFS_>f%P&=X4<<0Qn@lnCvcJDC{k`P_gZbK5 z#IGv1NZrrqsW;ho`+Q1WU0q_LVx@|nUEZxVD}~klxA1NIHLZM#by@EHuh*V!f9-d5 z;#3n;)3tGXt?q1JB7T#5^~6I?l@)?(>~iw;AMQUAcXw0j=|gwh&RNE8+Vj8ibJdb( zm!|(t&nRZkn!j@D?3CCZy|g+W$@j85mIp^f?5O!!^y$Q%-_O_G-}LX4Vfc|R-5;yH zeD==>4DX*+_}#}*VBgPA(lvh`9Bg)5Y-nt}Sv_x7Sj(k2*Fc`dyeFC#O?Q7Ry7@$E zjMIbOOXs(*zvXTH^j?=Bn-|cz1Z1#s} z?b0f52b79OkcnyCdkto1=59Zd_z>U(#BUGo@}{ z?Tt9C#Zo6UY?c}{FZ8~s`Zs=(-}1+ma&7mRD!o)at^WV{{83_$>ZLso&+<->Df0}M z{`@xl{=MSgwm)W1pEm8==kxa85A8e`aI5>e(3h&c8{U|l&^Z73NBO$trXbUA$IS{@ z!}}yc`ppwZJ-+*ztgNh0Y|FtY7ojS$E#dWAQe^+My(!E6wnYq_Xm)5qGKKUB%6Y=T6q{n@a?{1hL6U%D# zNnyb(mTy_9@Ad8f6(wHcxL^OT2f3ntgrAeS7Sm#+twS<#6Q&M*6VWYHp}KXbdg`>Pe+ zGu}6PpI5nk&zd=jGfbtg{rNq;UN?R-k77u4@bB;C_Fr`WINW0{{8;$m*2@wxQPI+Z z(%pCSw%>NHT+Fob`_uHeyqt`lm*SgK-7h|G|G&2&)Xr(e%8f41^v-CKM6e$y6noswX;_?nMLf4|=!FVOP)-EMtb+uG01&IT{@apb7| zez)BGUd7|@_v`J8pPk_pR;&5-a{1%q{r0uLOq^c){eFM{^Lf=$Qc`NZvr2w_d1?Rm zrT^`1x!l`-Mj0g>Zg9NM^Xhwv{r%c5tF+(W-v0QyB{I13-uVmu*{iF+Y+bzk+^nj@ zy26W+7cDCwF_ga19?YF0==}OyFY{;_Ox}5XKy)%U~z2)LJ zeS2yu8J^h3$+mN)H{jhz4YH=!a+xkC5$#O*VAeyOR6>8jAi#O>lKQyyDxURrFw zn!jdW`mA#bEsGW{KJZ;;lAVf{6_?_bJ0;6*e`}kVcj`r-thIpC`n}(7%`(mY_U5K> z;-QumD^|3%wcXua&fPR&_UzwxiqGfX-uCukyS$ub(UXUV+XbE0@Be4z^x~}f{hH@< z%jebqt8BS&T)ti=@3SfM9I3|%%93uv9g}v&=o#&=c=V*RuKVui>6QBXcP17-RH~@n z^T?%pHS4dhb*CqP6%iNT9kc(YYvk94x3{Lnk zZGNxPIc?=87S;iY@ET>{=!L zt!-}Jxk^Rt) zf1l-B05=@O zdf&CpYn{(acNIH%d3hb{k!0q-vCMb2)0=rL$@$k@uV0zFDp?}!O6c^v|3CbFK6k#{ zp1lUs-hQoe7I-DHVDE!gQ*+b&x=dr4pRerW&;C3-XYKBLJ02|JZrWl#g(c&C%k1_4 zU+#8}j;l<*#k+m^ji5g3zSq3J=2Tjm-!VFv|MT0Mx2h$VrDOM0Y`mKF_rqa+_a2Ff z)23~!`1q);jjiRvmzS48Y2a`>f4{W3o}uB#bJp+wJe?jN@_b$V{(m>q=lgni{J1>- zp9m<5-v=H4&n4-3`CxNYR8?77(T&!_R(k_JOFrMT^7Fo5=fgP`{%QKN)+ebHZwk`FZK5hE+epzcX6Z2K8zcFxqkI!@jfY2mNw4{{nmDD4#Uf3J>Reo0ZoN`h zuUttnkm%~}E`M{wF!>nIv{duFJ2NIu{P=Ww{3GG;bupFy|9)3jQ32(6PfyRgyQ|(W zdAeEb_t$U6x6e)Zomy5EmizYRf~9;W8`l>2=AP3v-v8&1_Ow)SalLBfpr&RM_bxf9oN!T#U-$&V)0KhryD`_3Y6$Bqwob>Fik=bNso zdp0+H(&WjHA3t8aXi<;b;;i(`1vh^?++&WH`FVbSot?$gzLT7uoZJ2On!YZNd@%Xj z$@AaOUcaw%LffMB)0NZtc|UgjSsi}Aa_Po}A6GV&uDAJ}rSNT%zieEwGy{G9& z8YUePkFWV?|Npc7!)>wN5^XE>SCz{anC`vkQn%X5_Tt+z;q6y$IG)@UT)O$c!SfU6 zm!@_9+8qey`YaETvzv_HD-ElNF)YLX(g8yK=m(NOxD*IuYaxYon;}@bt|$ zgMxyjq@@L&Hg4P~9$#a)CbQ%)ulWq0W#{ex%P1ZxlUY0jDk(a%h8jHP{ zZF}?PO~L(zeo-EertUHC-C6nM!RdJsRb@GIQzKd?e7=5Q!M+rIrx#nr&Gae@JTJCw zUTE`eF<(nSP11k6%>3k9W)Bv-MVB{nEL_&M%pps8{;Ycr`S6^OUetv%bd4n@=x8Ls*Xj-~X zNlEG5zTfXOgO~ZtGJ=j`NMp6!3wKD5D#GxGMAmzPhUK0RG8c9j-$a=I5s<=d^-t+s|Ae>rKA z@ZGiVzHiIB|M}y*V0C{`z@Pj-RiUM=UqY^DucoHv&Ye3$LqnJQ&(F)t`&MByAzv)6 zTF_~!z5LC6Z}ZQK*i|q1;gIb7_*-th^^WffP8n}X-}YtB+dW_3Nh7zy%IQUSbNrk& z>ssestGD~j@1(JJuBJ<9?vvol(l64)CM$5P4qtz7TW++gtLy%{zw36rTJ`kw^nM9L zrnby^b-!NDum3mm`A=@W9Sou7ACxO_+TH#ys)l2AfN?}d9_)laW*URHR)KG{a&=iC1KU2o;3m+am9;q%{br}NYQ zC-!M{u`Nyvc(p)ys`{O^d412#_I_lD2yZ7s5zoAPhY`@>;zae13> zRz2b?KOfgJ;qQvSN0-O_`gS@$Yn8v7t9$RRtShzrXZ@w8J=|ymi)FsE!`8)g za{u{q+26U1hx4FTW#jGF7SAd^t`y(@>(A@UTbC#QKHj(Y-K^j8yX4c~v*f+s`RS*e zZPAyd%j16Sd-6M2-T%A)3;Rct1V0zQ_mzKlU;6EhdmAplzUK9k`NSrk>ZPoc6qC(n zZ{EE5qsYN^Z+E||eqnb%X@1?;e!Z=U*T2R7C@m}7_R2ba^UZ0x(Pq`(a=-yDJ1bqM zpjyyr+rn+f<286T-12){`(YM)zR~?J+aK3!*X%1e)+5=>&VTHupskd-)Q-K^6vK)n z`xM^3{X75th0kqvKQB$5bwj%B1(*LUK|{4eQ!vjcA z&=qujx%O=S@3r$;F_tH-DeJw<6TAB_J;^FaI@T>!r8}-Usy_Y~R3H_CPT6`Lw-z8~>YCzZ97~ z&APd2Z`_|6r#jnt%idqn{hJ@HYm@Trko)B=%U|C3k<6j^I3xN0+rNp?0ej=*AM9d( zK4I_Pmj7neE6rC)Mp!X-76%J)CK2^7|Frw=OkJbZEM7n<@LWFL!@0rX#L9hQuPC#Mu5Rw#U8Q@A_1|x}!7bmb;@PCI<8B^k zH2$FlpP3BLO|`Fzo41!=dj8fnJ!Q*tt?OQHZ;RjbMoaZB?(LLUS+&ivUGS2gqGyn! zE|kWGdS;9Rjj{@`$`evL`o`fw3fM*){W7Rk`FSH4SDSL@c^xfihR-zD{f z{+Tz=Y+8RI+`jMM#$CI9Jvlj)gXq0jD=FQjF*Oyz( zeYj6pYQfIEKQ3qH=H}+*zHn@V6gI{ z`CV-%T$&FqxGLp@bNs6(PNG-F=El9;+uKCN#rtI}g}yC#yK3);uX(oDs?y#|MowG& zzT?=!%!Mac@^9SxoU8WDZ=Y0?hz&j0^48dHeHD_Dx1_Kuuvqf%de(Qd&!%bX>%Twt z^266{=Qm!@U+2zo)Lu&de}>Irg9ta~{>2vRZVMH*awY^`>7e?GM)wEx<0!<*Cgiu6^6Ih0g-_vq z^miGP7aB5BRURcB91H)Q|K2}KuJyX@i(J{(2XB|Qu)gZeV&)T3o$Pqnl>3f(Kx=gQ zZAWEU){dH{lz=yrzX@&GG+n4_h50JRiVBgmy2P7lbN$30sm!!%d++;tRWsZC?(47r zTK-M{;HG@t&FzmN)1mjgY|iUnX|v?(tHuQ6he#(hKRtYy&pbDG5tEcno$>!&Zx=MS zDYYcLVP&^$y?tulrs+aSAoC0O`(vt)?7W|O&giz?Mo0Pm<>y%E3vVeuzU#??#xSo* zUy6U74{B`@*p##N#rjLqJZzIsvPAmqJtBSeNSxP>1@~5%X>=Wmu51yQern=w?aT2i z^BQ7}i=KYln0&nKwxjpmxwC#aCOx_3@i+8WoP^85oqMMUIH!h4Z-{C7E&S-~)!z~o z-rhxzzea9OJJ?Y(OceAUtgNL<@VbJYG$*0??lzUxv}xVg0r(sPv>oC zk5lAZ^q^91+n#r!#@@4Tdvn^ByZr)@6H>^C!7D_3_z zp@V6?)Mf9QptYa`q_z0qqDg^Q<14l2f6DTDa>Jt{=C#@Nt7}#SdQN&O<^3vq<&Vm; zcjaOF>%*=lpEFX|^*ofy(*9t^;}<)86uxe`K5t5R@P|u(OJ~2+S|&VMAV5-ol@S#}2y9xVipz%=0_z<9yESyf0bm zKBaJjV90{1%B}Z}CSF#yUaPKW&*v^^@!k6GHuaZBRW3-iCC>V8`ddod%EeKjBq%zq zsycPfQoqLu${AuZJbQC2zgzpSv*BF-`|KNb@5x`B7?;l39RRK|zlQxiFqipmp81pJ zrm_N=;{`n`o*%xb>3A8W&MH{2?}31T(=s37$!8j_D76TQsTOF?c_8qCXKIL|q`UM* z29++QDV-9+jM=#p3Rcch;IIljUN~owMoia#{_ByiOn40)Ki?{@T+p*fBjR7ki=dJw zg%>T`B&9PpFVc9UFirM^)H*Yn^A_*ce&K35z@>BkGsnULUiV$6?>@=i8+v|I&h1}m zA)cC14%T0#9P~E6`&f~n=xt;><;;U)&ZQMv@@}s`ymK({SN+Qs$>#PYK{48>JHCLU zYtf6fRT|7+J46>Hh%exg+hG!uYjA_dAdfqB)^}6q7{+t`CVgg)jAV{;@*NC**LX~W zStN2=X>-YjJ@$HsH|g9f5zbn@cT{U&}4^e!S?E@GcNi4-O2IQZEK^5uWR6e`{oj zP71HT-p!`4MB&ZnLo4LxpW4hE=_oLv;eyANWs}w@c?zB06t{kQYNTFk_bfTqSNx~? z1P-MxU`&7gQ6W%7H2-$I9G2%U#!;6F%ipG zdV4$JK=jMdHC&QEMB{Ew5>AznXpG-&u&w3NbkGz}gw%rD>n^`MaiDrl|BbUxEcmj; zG`O!RtO;J=zCqMLZ}F`7W3M>*#HSp5_%wijAB)~%F300?sypU?a1s@2Sxi-G9nDZ0g6?j*n+;T()}2{6vXOMeDE6{*kmu z#nb0g{u?fC!DOWmuj6(n7(boU=4Y7c$=_py!i&ut4|Ck(+z}hBVDdYC3rHney4Z?YAF)G&sp~ zyijfO$rK|=p0+p%E3f4<&bh8IU!^K*Ghtu-r|20r9KWs>@}@izu>}{)1@&cep+&L{6(t^s{{$(|&5jw~}84WxE|3 zjMiQ{>yY(&hY$PLA8I=veNiuZqS&*^mCyY^zMI7M<;%Z#zPO~acb1>A=Iz-{?;osR zmE<_>V=n)n`x}-%Jn=!fq9N3DiS#LHj>B6w1g<`q(BKemv&Z4+6d{`sH%(h7=fLI{ z0?~Haoa;jjc^+Fmu-f`+%J&`ND}z4RHD8fln!zzO(5s)JJ7V|gyQ_Y#zHold74fUr z#jZ@78y{Aj?_1F>u2Cy$W#)BJ?yAx?i!7}#g|kxbXy^nBteY0_%K&5plZNII=|*Ob z?Ao?CH_!j!0xWaf{cD4|!U80hW^`)xi86T{o*mpD|C;TkjU2z9;$g$M5FbrPr_?Ez znoFv+1$p&(R|_^R<8Eq5o|j>y;i~;YM0lyYLF%jrt_Hu2GP!xKTw2SfIm>x(pjW@Z zY~k!3w-%^u)vXdbw$a0G>h#o`(JxckjP|-*(5&UrS}dZgSp1*YtXZQ=VR2&5WuGd| zlaD`|REC|@e3-YeRI;p4Sf|DmOa()fuckNunaq{2Z^zu}%`wgcwT&oMX z)cP*)bQev`X82^o&)d+t?2z?2hnLA0G}XGkIdDCDnAjf8zpc%C^NG2v2}|uxtXzI_ zfymi~MqV!k=lq_#$hkzeptbzGMO$JPch>8$>nGJyZZ!0NaXVZ)S)-OkYq7}NgTW7* zoE5&y@Sgtj5xUc2av;EJB0El0}5H9xq0oOh{W_i}+PE`cKD zJEi46R_&GRXAkq>%-7If+V7Y;Ws%`3#(;>~dOb70rg*bBHt2pUu+w;ZE4ZoM&oHox z<;Jy$>5I4@Kbf?C!DP#?CaO~wiGq>|k45>kY#q+m!aKBg_$j+Z`_Hra_)`6=y{r>Q zZ_I?#GkkJdBsbprbD%lkRZz)2Fa6190=_Q!!csE7s_WQ+u&!3Pr*$2 zd6imLnkT1OvMGw(Uw?nj{rgzY)uX&s;9m%|e;O)f3HtbVUUK&s;7(Wk2ST_SbT=lHc;m|K32 zvvu?4&FcR1=1iV^dF8$Y)8`g^YA+uCzc)GfebLUYuC8tQ_v2z>*8B=Kf3viuyEr-L z%k=Q-57PF3))hbCn-i_kRrKm>@YM3KPhtP|#GgC7@%s+*w^n6me*WEV7^dx{k@rQy z#;i-gYx}Z)e}6t_@2xk<*mrRx;=TlK=<_T zA!|$a2%S3KD`%`>`0-@BoC}BPoXoi0nV&l+tM9M-{&vZ~zju9otFPPt|6P7R|9uo< zR=Qd@^WOCst95Ia->Fah|HJ+9M~7UA;E?incXlQmY}&MG)4F*#HtwBL;8=fC!u785ez|OR*!sA+)2ClAG*-ylV*cccxR}_p=g)u3$yeRGkSNaQ?d4}Qv*+%% z=|W$e*dKpTos;suOE{Ql3cnulL)&?9lv_Z{~c9OE-Mo*ZxjhPjg=N|Cmn| ziHQrn=7pR+VEMI4!DEuhw6l)2(w5)sL2T+opS~o(EaB zOvt;Cf9ci3|0^Co|9|>@Dt+%xLZ^*1+m?ibOcGs3Cm5~L z;98?7TNNHMX$dR0*n{oUJU+LXo3pG~7`q7;Lx~c_(<(2lb37TZzWSR<+kb8@F1h=k zjvY#$*IE!5f6Ctag1|{jU#pf2%Xj~)OuW>=J=yKdj>=`LZm3R=4f^rt=Dys>$Vf*= z#>j^4pVIHEC{LZ$?&HJF#dV_c=b`7^`a9nUZ91^$_IpO@(Ercw*7;9|bUvoYF>W&W z8fMFqIcen=z3JI+Z*ASAW50Fhi>uG)S^s!*`P+HE9kXXWI5O+~{@*o!KQCXUcx*ZU<5m6Vi{4m2=sPCsu~`btDbUr+DcsZ(8@ot?eCd*AJP z?d9clVslq_w`7~7T}{Of-sN8uDq>SSB%97!e3U!w>gsCotmg0Y`N#i0)m!cvUb$+M z-K5pskEC>C{>*>h6I~!Kew|HI(ce!ovYH^(yZP>a9)-;zH+ zJ}&p4-**1@+wJ%Fz1?>EP_B`xh=Yq@+zrm>@kTtGYk!x;)+X1 zZC+XP`r6u=GiOFdM*7=)WU+htZufgRqm&aX0vA7e{CIbH;3-R%H^KE;S66lz3Qo(` z`C(ys!uZRcg>R2~E49pv{CnnOmvH}@3YE%$qUF;!^KIj^&DS{hQ&Uq@(m0LBX~m*N zk6L%?+id->8TxZV>Sgvk{b!x2{#AG81%}6#eKid)y&C5g@nV_zu8NOItFQig*e>5E zVW_05oBQ$6QC?nNj)gBTFORQ&yS1HPUd}u(CMoIB-12)rPwVeLp!xlN{eNEbI|6yt znznsfQJ0gyJM;*)NKO>Kc34m5TAZqV&F90?>+@s_Pj*NaA+NOAor=f3>V9)HG&CekvqFM{Cm&4E(9^rOG5L6pq;bTwyE_V#-Q12% zkFS%=GuB-AEayguDjw(N25*D+Un#?^l;ZMneuzxbf&%y5>x{M_7J5Bu0t z`7i(Z>^+$>%RK+yy4c-*b1VvviiXSBR*AIj5_R4A^V#g}IX8nsLrv@d{keAS+VgqU zdUw)-oVZ?2a8k1l3)=qsP2X{~$rs{8E1@&*3xk4eReLeS9p|>fPb*b}k%$ zf1K@qtS9^Z;BEOIw%u#amj66=&!PHT(ks8KZ-1ufJ7pX?d%b+6*{5|uPX6U7Th^^R zm$rH7k|ic)W=btd$;tZrek4UyKWdZCGnnZ!zy6=4&MW4}rfb}8PYyh%xS{9NrXJIf zX{pTz8%}T8w#(WgTxjX!t6M*;-?~&(QKjqA$yc|;!n^NpK5=W)=FNv|nXNJx#(%5X z?$3`-Vf9xfyZY^ZbtKNXoxfjJaZBdqWt%o_x^^wB<-*I$%f)r0 zS_GoDWC;Fc`(i8NdNKOzkF9^SyB4Xas60qA4K=OvKfgoialqOBCljC6$A0v?Xgxiy z?xl47{Y&>;Pu^PQKmXq;?e#ggwqzdd5>1)u*v#fT+YFSJ*_stivLEE%*&+D-_3h2# zpPxRDS8NfQB(%oaYJR6uw(@%|)h{KN{qO83e7q_3w33q2y~^iv*YE%LYg%;P&E4hi z8yK12?Rvd#ZS?lIf`hE`wO=lRJd|{#L)N-1rvC3&j)ms;Dw40R3iY@BD)M9V>aev@ zTeC#p_IwGg(3ZEf6;ga+`%bm^)#Xc<3T7T|=gY2e-L&n?my+3Mx22q%l;5>)X8W^; zkB|4u$8SzM>na`_5)vXZ%jd$EFPl4==iZ7g+rgulBAxZRZLi{n)=P4Cc`7cw{^~tl zFLqbS%J=h^`Omkj-8KK_)%t&*=RY)?CZr_Mb}{;^r@mTYc)>6G7bh7Od+YBN5x1^- zvSRTaK@XmQdT#%}^8UVBu+ygBOXEKAm|Jf1O&`81WjXKX<$se|_4DJ* z-t#36Dyall}SjB8fLa`HM96ZvC12XWAP1=U3dH zxkatL#x7s;;k5q#nEiFN8s&*xOF@mO)G3#gH|S`GdMPZf+AB9j~X7$UNtH@w>4zTY>E~%s@8nibV|cD*+F~m@44=6 zvMcv&46;*v>}T6C{btU&vuBS!HQ%?P@V$EV?%JJu=fAo88eEfKik%_$D*FZO6H zzxV!{tjzJX(cAf^7n<#UxAX73b-yyI?QeQ#aXDq&-BqgPTPRy#DqP~M+;^JeREj^K1Xj|H|K?WyJe zOkUS}`bO@p+L~o=ebr3yUD5VcybIrSeciHmih)z=lts2$?IO>wRPWu-dG!2g5K#8N z^W)I5H$88@W?!>DC0mzWHpTkd`pEfnC;ImB|5|%$yJXz@=`kv*Uk*pw=IX1)T##dQ zt@fB0B;qRK`r^i~uIsO^u3o%&@yWUEul=s>-H`T|JNp`F@_GZtBG;2MiZ@OAX41N6 zjz*VUzk8sFOqJ*+zuFV9Mq#7B?QYfOpg!@oy}7-gKYeoRk=U4Ukf}&B=)}*D+Da;r zo=^7r{MWnv_iA+Moc?4Ze{AN}d7B{}t-q<)Q>Csrafo z&S#r^6RBP|Wu2LK;@WS)7cn=pIwSg{g?m&?4u?L|+P^Ml)dT^jV@`_;yDp{}&Gb=Q ze3653$-?*7zfXWhg5iRA&(%BOy zI0Ae#u#)gr6*LGn(FcseK`% z{}egLsb~E1Lgja~=|ykjiM#Rkn`QB{lC8WJ%jHC5wzDi>8l*7`+}+XWx>U7h>!)*G zdQ%?U|}`7~=bDmHRGdyyKMCczfweQ=iF-axMp7w)Hc^w4Did z;^^cHoU|lw4fCVjwx9OZ{@!(QUfUwJiiO)>osE39;mMWYUuIXNmwvG@h+lsy{k_Cg zZLX5!mMgLE)Z!oKgjhJaZ-KgbMbm9tIsP>_do~+be`TqS4OA#-zhZtsu8Cd5wQ<^k z?t=STUhxf8i$!z~zSdef>1JZAP~(&GuQd)buYZiuRGpEuVuTWrsZOB^e;md6ROtXe1n839|A?jr3jE$H-S!MfVx zZ_2D!EI*qz+qT-w&aUiDM1e>8*;%REZ!@p-y1R1ym$J|cno}GW6oMRaan>S@U3c^5 z1fMUIQQ7?ZYt^3ZvFu+P0&eA)#rOnHsr~)!X3jQ-?`~~6YU{5@8*X2enJw&e;=}&7 zj{PnVQZC$^5bXa_8k`o+9r{vXleaxufMr79;)@vu5>|1uj)(`j?Y_n18mQt~G;h1)K=sxgv8-qE&=p%`?!91!#QDmgn#ez8x~f zvd?skpIm94(|U>b$i>|^h- zSJkVhYOy}Q^4Ry4rikx?c(tx?D}?k4-_%AtGtLgXVv?6>Q+4p7@$GXfF0EMM>~#@5 zn5g)4lJ`Rv#}`?Cd)p*(*eVonu!bJd;0<1w!6YlaG=pC=bdyfCja-CIyzuKtnwKuR!4HRIU({y#>&N#SDQi;&FoN{kP)?T{_fj5@Rsm*$ENkwEWcqA)m zPeQ!fgtZ&CxIFD`YJ2oUolCXig?Z;C9YBMIR4~u97Tu4>_H#n_@m+rgFjGDz6V<2kf+GKfUSLLAO8= z#d3`pYlWj{Ixfbp%f5I0%-vHLXR3PngW||`!9s)OEVGUl#&k?}lx#c5eOH=Y`XWOM zyIUdiig`gMji9016TFW~tz`W+@)z!xdm^;`Nce@7lY&eZZs++Q{7Z=E@D=f^@{)B+ z_HCH=d+LUiP09Ns)?b(AVcQcVe|F_^$Vm8wfGY}CM~<0G&AcyE#U8LmVD~JzMOWsC@153WcjDWJ6o7rb}wA9aN&xBh6e+U_qWY?w&)&s^ftpnaq7|U zE5EI_PT9!UqB+6!v9<2y%*nU37ie@Hf9J^YGN@!jgb`1Fo5cZ+Ewi_8%jMI$!MgrB z_rmZG>Z>5LI<~T_CutpCF8!5ZLGY?G-pywnyqfPD9Xse|GtqaN;SHX-X}j5zq;iy) zj^Aw5IiV4kZ!(4R>nbztE~PFdpUQ(=OGH4CdsQfCgH2igB8^4PJu=ds(^kgC^>%ae zG4iSDdLH6>ap(P-xHw%477JOf4`FtNg-LhTSlm&!HF+{2pZV9*FW!}=tfx5m9xh*K z|8tt;rd20d()rQ`Lhqk9n>pWDdXf}zC!n_u+S^TpGI#^ zF4&~Q-NYdM>SCl?S6hJO)gI&O^C9}{%ifi*>f^6TRhXu7oiY6Dr>y(My^DJbH$QrC zux$G7T5UnuMJk>Td<=OmZ&-RTUwXs$<(FT+GQ0XySGjAEisyyxU!&bhIs*7Jd_V6? zyZ`L~S4C&H@WOeQXZwZUi+s8KjA-ue@|Hs9WV@}t-$h*oSs34E2tC@mOruspYw;}x z{w47{KTfIMkn`}~IbdvSe3>q2Mze}7a!^YU*B#&-32 zrk!YgdFboT2iFbEv`!c8*puuvza?+O8eRj17kcH@oFc9dgKuBE$+DoI$D4QMsR9}H zhZYYeRPBvZ^=wS4$Tj~L?!c|$c}QF7@beW~%-ZL-OxPL% zLq4=7%2pSxwz!kFgL#pL(_>XnCuV_|!1dP;zdLpJhRl}R(mKg^b1ZKKS?v)~JQ9D> zJ+J#orQEhv?_Y(T7xAhN$PZyY@k35UDRRohmI>mDtd8Q+>8eig5}qftEA}oDKXu@R z;?4%?D~~@`eCTrduwwGwzzMoS0W4QPxu!7M*!r$JyKog3*Mp^RPkh>>ll+oB`h;0? zTIJq2wV94WNqcz0{u{hgVwcv5-oM>U#B{@Ar@i``PxrHEEshfEIPQ|i;<7KS)#Q+1 zP}4^H?#5=B>xAu_uSN*soVT>j$L&7^e}~Ufr{J|8|nC;w~cNrZ+4v&vO4EM)dssqepZqE zdD0!Snk(yUeTz&O;=P|{PTK6bYL!Rs(Xy3)UTpB`er(O4EVtxK`|ob&m&%}d_o7+% zN)Lz{sx^IVtjUX<)~cC2L2iwHisYv9p7TML0XKM$Xg#x5?>qfK`EBe8bLY-C8_Hwc zLishf?z8-=$ZY=R%BtW^I>(MD-l6ddQg(X>E1h^%4{<50q_(``p zu(J5a+Wer!4+KIqJy$X9%ddSMxc8gy!B5frmb;(czOtdlgy-;_m`WkVD?i+lZ~13# zQT7Lgrxf$$n-OB3ylW!^nQQCkaHO0wI{xg)q^5|?i`XtT&iZcdEP3zL@;#H7Rt7XV zXJ}+Kh(~Pr5?1@@k;@vsr8k$Z`>WS7;i(k&k!mi!gUR0=oI)-=T5{xQXT;+Lp3Kwu zKAe5`eYXDl>J7G@S^g6bGvz;ZZP&1JkqHsF_buR;M2Oo~#_Gia=Q^!#MaaK4yZ-Z; zzNv`miA_8|y*U>CT2vL&=EzfbkS|M`MdP&I;g<_l{)&G)J}>`?=|qLa=l=Q`$uelQ zyz$Y{3F|1ZbPaUqaQt;!c%Q=+gEw6-zb`(x{^SqiSJQ&FG@Z)WFoAJ~#S`gc4^GV6 zXLREqw)(c< z)qb6P6VDuf|J}phQQ*TF&qIq^{&D}_E|XjMuG}m?JJ0q;*KDrWx{kAiec~Etw=I>| zKPvKW_Ntri%rDkf{rK4^-TM3yXqHoWMNbyb&W|dUOVV6>UkI@7p75h&k&0(Ul5COQ zLY3)9;LWVy&XIK2k#&KP4*MpZV$C^~t8Q8xeX+4R zCVywkdDfLdpTeqQ*<+U7_Q}=sZ@%?t@{C5F9hnyLEA>0Me-`dIeYa|Loai)%g)E#? z1J8EMlze>WeaqRKp&DIEH&`VuAK5uuprbi`+KJF-CrW|>Os1bMeQ{yor%#`5-MV${ zTG+hj$;ruU!(Mj?D(i@GM{-(g71_cF0MRoP(+}UAhYip~ld^pFfe0S8RV?mNjGgzkv<~D@PoYEiUvN2cAdFwu- zF9(-$c}`N9aq9R&k5vMGMpN!SE!zA2UNvYOqmh~Y*6uGe43qPAy<8?~oF>7;7Q^iK zG{o}65*Mv5rBIIw8*%s3k2QW>c#JYHb{RB>roRa`hbFvZ-lMgzLc1j|O`WYds~}Iu z_tWXswm)L!>%upbGwhzQp@RK{hKgg-^7qTP%ulG$yC=xs=~I!dU}P=4dy!oK^ONfH zYySOw9;+9wkZUmeEVr0W#Et^R^Pjb*i}f?Cm}XJ<|8#7jGpmzERcy%-d1Z^fX5ag} zHa2*C@R$@55U`=_ZPfD1k{*@aM<>mmy*uNglE?R~_r;A1vm6Ed@~z(5Ju~}z^T?(( z2NN2W24yg4x(XxDrp-E`5jTVRnC;0cr3K$lZ908G@m2o&^9DTUKeIJA-bw70xd~dY z=*(|h^5(|Ib=y*2Tv+(}+S=V8k4c|A>hj@#g@c&dVwU!TFHMU%7XJ8uf|lVspp z5f$wh8anO&msr=A=Tl}bcJIGe^Z9JQ?YA4s{WebL+$VD`w%Bmr;)cbK;|J5f&1)3( zJG}LJbYfy+U0vPxH@e94aL>0F6-{6%=UXA{1)2`O#jw)o>+ILA?GpbpY&1O;;sleG zqU^F8PZk(i&lulpML#SDyQv*^`gW@_BxZjfByV=@b>Ka^Y34|vZd*2OEoVzr$#s@%3{%?=I}NmE!HA@Z5Y zI4&k~Ym3lfgMRyeKR!J@eKKqLnfi*CujS)xs$x?1TkOBy`$oL{VrX*y%-`vrAO3u~ zy8q+HW_Et5-eZQz$0l^X-M6ZDtLW}yTJLwbYwGA+xpwc&8K3>>hCIc8-aRgwEK}&& zl4Yo?wQS0Rm&%RT_A=W1=N z&Di{*P_MyO$8z5M%^yChN|(DtEc$Tp&!0bYt;<(kbNjeEMswa9uBH9goWK1NOOrUZ z^Zw0%D*?6srLPZOE9i{{F9zA#*rV6=HhNC=>%%uyHR`e z$Lw8K+O&_|-}0#U?vhP95gQnkW-?rD@@aBjp}XR%-1lF<7TW3>F5Gxsy#H=y5O*@W5Dq$UUrK=V!XqdCS?!`^r=ly$5eUCB~J^t@k`1&#Q&$+aGLCO-*HGW!-o5gWoyz@Oe7>*TpaQ zBtCh6St+egX2&=E&9D5!N)N|feH8uS<%Hrq5w8gWl2;`*IvtVLDE+Wt((zcm>!8KE zw>3Y@e|tT>cF)(Rzt``6a$!2Vb>0Ed$N962{wMw^dwXl^zKP41D6>iaTIkcqbK%}w zecPSi^f&kY`_cQL@cQ+z_c!;Ye(aG}34GDEx587`e#wp4a+M(E?83NjV!eyTWIO>;4>n|9|iIoqMXkRvj)4 zeqMHK#!P0&>8vgZSg5**uuZvu~DJ8G2tPEc6*Xnuc$&-|d>W8i3N-bI0 z+2QMAe%?s#Z@qm+u03(aKknb|e*HaF8mIF2N912U%pEGC?v(NS+uI#Cj?Dc2Yi{zy zz4y*^2FKkgezA&kd)Y0CzUS)aY<@3xz1ANnaiFHP>8H1*pO^b{edBh&@6kUyRW^!>F>Hjt_xY5`TKgMdXI@}ht+&OYYy75x_zc?hgMz38Q()* zrwn-VpC*4!S}fmpOw+lb%F~l`otEj}n*D~)ITZU|+wgR#R2Eca{rdSscVE}ty!dT7 zHzz1MZ)jtxnEY$rzF5Xv)t`3ADqg8SuweWASku>^u0*#<{I7YuV$$FFC0FDANUH9g zBJw?EPUWhZdN+J7&XGHlWF*zwEw1mzA!}KrawqMZManTnod-+0lFe`M{1yKu&f+*p zrAT1roDFg{2aigbWqx24e|+WSrAwElOqt?4+ic~byX*@X&E4e(InEm$rk#*@mG&v?Zx;wkW-|ylE+mzhf+j0+c zpPd-8_!V!uS&qaGMV<0B%+-kpwp_g$^W)sS?sZbx|DU$siC$N>eaE)_ThzY4JUjQA z+r7}D{?r#2Cr4jxKU&}=-^^x{$$Z#gYI&%fbp4tye}e8e28Nyz*tu%*@y7>`@+{-v zo$Ye%+3uS3`~}R_$&Z8toSgM`JXy5*m{Lp5Vf|etXDV6(j!txLyz;DU_d{08Crsw? z>#u*d@lTzyNDPoF!-_g(hY zl2)y@xG9YSSr(zq`HM9wnAV@o_;Xf{h3Bxx)S$bstd@E;-Z!|letCw+`BN`0E%g@H zjbbVO9$)wK=_1$exQd6Z1+(uwt~h0zBB6GV>EDa@eR7g@NB-)YTc*vLF{8uZCNy+q zqVWmPEK^)u+`f{RL7|eXul{1BDzHp|%B zKWCSRZ?T%a|K9hH+vookRy47Byy}~uVz#%3N5J2&PfktV%DOf5^Qsk9K_<)7Q%kO{ z3SAwxw#j1Oq)C%PSBLHWbV~c7*-m$byZ(V9iCUhb7x6Spp1zMN}zdsFJ^kfc`y7GZ0nOp}gu znBT84Hu-z!%a_f;pJi`YKRM*B_Uul(z^z|bK50I8*PmIrSfz8K;l|1DYgglXiW*7G1l4itKvfi{>9{6;wTiSQztjTV#WNXz!e8>-6H1 zxBgM}uqppyLgQYUvz@s7Xw_;hM+Fnro?N?pIB8^Gj z2ZPQ}5wa=C36b_t{d&W8U*^}YMGk4^IVMe?1<$5^-ck6t!1lM@jc42cW&bxw4qy7_ z`}}kF(_B()Z{EDQ>hAp3dbzD9&JD8T>ZSBttn47&YJNTvDFZ~xjLuMYu|SLI%qtunci zA7wsercI@hUHSEC(^Ud_HZe}pcz5fQP@VU+{^%7Nrxvt0e!j40|Kk1YcURBN;#lN9 zRW;_@qq&hUFR6&+E;L#t>8Y=J^pEMWPYaHg%wE|X+W3*J_=n-SlP4SZK3lkY-_w(> zj@wdBPwp<5em`mBlP6Dp=(2_TyPce*a!_jJLc!@9ZggKa3CR86z7TvukiiX}3GXaNGtds`>Ve_Xz2slM+N)k z-Y2%-4ULa4y|l#hiP%BibH>`w?tS`|+|OdftlatNb-(SVq<6YYmaU1~TXkuPr|g`i z+g}M^Q$J!S-F@AbE7jh7%D1u!JdK#MciHgK=`$5K%Vn$XsJ1xA788D7F~s*vtD% zZ4r1f`}NnVKg<_|&0}0S-n8cL_#U3ntn=yL<$JcO9xHmX)D|y&>^1lI+ztMJ8>X{O zn7z#IF`_V`Kj7<&uUvU&$KwiU^UpXxa|;bwK!<(JQD&oal$dE{O6Dt6X9=q!Hf zGTW!?9DDrsY&H6K`Qm+9(Km-&=XEPoF5Am)p|78Rq(hKfOh;k5QtKS~{Yp-grcK+H zcXwCc?@tmFgyx)VPPILat6o7bg_Exz*n+jodN&0%wHY z-njM0A2;sgyL7)%b-{w*n;(;HGA}LR6jl=v5m^(vTkQS6YldRos^;e97Z zijQ-Ty;#1ea-O+VFIzKXo0O>Q&uPEK6ix0}$}GQKZe_;)J0|b`zPWeSd%BjDeS30p za&b}7pJU$JuBZL@e_YYNi_h@i#UCxMoO>6}e_gcmz&$=OkGJ#oZql)SW+l}n_2|>% zN1q;l=n;NM-@y1Ra-cLU`sPObp;-3EF+*EfL zmpj$(L4ECfZ*Ol;PtVB6n@bLCNed5G{tV;*=l{AG@>Q)_06OdJM zS@O6!vE;&;w9kKjetv#_{`;bxUS3{a-rm{S*?05IZ_J)I&+pdl&<{%f6`2w@-nC|F zfD=u>7LTyX$>i?}Ej}~VW{8E0xULbf?E4&6rF`6Nl7G?HPgxo~%U`dp+UqMnTiCkl z%ZoE-d^9*&6%KCn{@eMi_N>ASx!vkXJ}g%b^QE{39;qwLfAM72*=L5y#~%Eh()7n7 zBr{oIafQD)7uYtpOWvNo)w5gzU6dzgv2ofTUdtYxowstLmTLafo32j6VyY^-o=uS#ttc zO}G^%u_|Ew!Bc!m8|#lOE$ZwR{&?x!hnCMPYxcYU@|?s{+QgNxw&njuwN)ASuFKTA zo8)=!pHsI_bt+?*0*8g>g7v>L9_)D?RPyA5_YP^-m)rr8yka)5d(9)-wyz4AIb)`w zhU7smg*Ogjic7Y?jy!SV4R}^#=T%CSoM#pEq`Oh`K?>K#T zlTLHbqqUw#xh95Wl__v1GF#1E_ccL#<-#`#VdfsocgHN>?aDs)m)*_;_A+D09@{0m zW1i=x?`PmzT76+=74HF0#|@8UY?fAhx0;~-!eTdQPvioIz60u$MHU)dX%3#3z$eS) zkYf|c#(!v1GKWF7iv0B6#l0!sHf8<4XGDWf#q*nzxUV}=VsBi&frO8maEsUqq0sZC z515s%Gp9seGfy|ab9Tv`)dBe-(h6*!&)hQ(yu5fpFwe_2i&?UAA$L-b9eV!#oxNPQbGE02SR;~NIC7NIMVfg*NO!zYP6aoprS%~g{9;biWzFP@GE z@3Pj|7ji|$o6Zz6TG5kr?BrDS*XGx+i(QGb-}Y*4RnR1dy9LwbYka0|dvqpHXJUk~ z=l;;Gdh$PZMiiWUsqSc?cT5{HETgcVs%=I>z9y{!1T-F_G4ewgW z1fHdv#kfk*%EhQn?x%ESB*`$dWu5&Dh28I^BkvE$Q5m3n90f?+GsMFPjlwZ{$!PnS}#kiIPBWJtNW{G z^P5dB4z8MQmlr0pZ{6-YvHN$*J@QdpE#y(Ddo;l~!TAr{-br6Ix|kYQKQXJ{!M49d z;rLt4y6VuYpcC{KS)TT}{7O^GDK$j8?r|fZ!y=6&(ZfmXO;4?*`%EXU`S3ufXFf!IJ5pOStS(7XGOh6ArGEe&l8{#7lEUZfd?uPzn61 z9;zPow2Nsg>sAYGPIo)i{c~hy3v;W6I{NKk%g{Zs;;9rj%jzOcnU!~+txS_yBW0+T zbYXRKO60R3iz11Gb5g}zCqA}t4LlS1%yB)R(&Qa3?I#R)BKs{*&)H!i7$y=T!a9jn z;R6Hv`CWWFUYTE4Zn^O9zRB&^Uyq&bQZ5#7NLOTJoD)Ci#Dj7rzP=r&@3yVxyW~IFa95Ub_6ti z_tg9N)TSK{k~#wGnDzSaPTr!TX{Iiga%kuMm)CzMvu{#}<~cmW$hY~w;f7pJ>89}v^|xLkv4`XSCHhF=^^gn7qJmM}fkV<= zTKTwJlI5|W)!ScHYV(`l34YgD_2PquD`>F0XZs~@wW^|(GLz37a9*v!^(CEkw*#O4 zHSw#5XF2a^zIlyZ{ZzuN@22j){Y{4ila>B#TUZ&t`QNH-XBRB-TKQ*J(S0MqVC6^i z`;RY-T6)+!l(j^2*NHnGcRsdPc^qsq`aADk`p#oai^bj*ZU0-f`~3>nH^v(`$TsMl z4q96B=$-JBADWSDb#k|Mi`A>xqIk#EDVt@`VXrayeO?ZWkMOT<1YD3m!(OTD#z zISXibyun8GyPxh2%|Dw@1GvEfi_vmgsq&yN*0AFfTw^op3$V4QukF*lI6?Iha{0ZAjrg(cFn zj*941td{qjbSKaJiRQxv<#QZaeitA3+&_8l2cdHo6FXCHw(0V&W7ey9wo}{UpVvH| zibJJNxf=vKjz1P;VN~xqRHm@OQM2M;z_G_49qgr&Tx(BrG%cI zX_W3O-*G6lAV$|O?vUW_0?Wl0B_8cvu2C!Ws+WzsFa1zfhq!=J`t8umvMJvL%ho@b zGDFhv*~+v4?TUY)j^1zIs`%$SgCt|MA8G$vbTK zc>>??P1Zd=bwXs2MW3ktD*vuc_l>kJKhQn@Ii>o9+2K869x8DR(tk=q^_b5w9-SFm z@v?f=k|_@s8m;2}akAY`Q_f#y@w<&Blg^v{OlZC`DRXgz?1reHXY183&-9q7z#jdu zYlrc>*>_nEEc*MyG?GnfnULDlboSH-{wcOvKM$vV5DMG(^}*RS58RpVd)|>Vie`*o zox5<&{adZ(QVO~4NhZtZfp!3zHk3>c>00*6@$shz-4ic<-I45_ceS(n?+th5_y@&> z&sJy^pUf{?`95rc*7cxJ{%bm$cy>y3t&+RspmA7e!r8-n>xzyihgNTBzV9d*YOyzd z_X&BkPya47sC#|5ps98?Ks9NS;pZi%7e_g;IE#IdJ@?t#%j22LPq8r7KR>1g@*4fh zopCDi^%bl8zSe*E7G}jQYyMVJu>GWAJlE3Opkr+JcbBuw(0%uPWBAg0XmM!)2ILYw7Ztf5}IT$^gUBo zvGT5=9M9YTLX)abFKyoc@FTm>h38kxyiH&D+ugZyzjjJMywfIUxt9mte|U0nvHix{ z*GpY(IC&>t42tS%dGhbhcd-a3XIEFB?|9y3++n@UeA+dh^@q}Ib0U3p*xPk48YiFMzER%nSzI$#N->;5(*P?JB`=0r>V;>(I{l4XO?~>7sqxYED z|Fx}ZG#*Y`S|)I*Miw^tMqnt2uZoUu9)>S>|R{%t|KW)mhx*2 z%j~MPg<7K0->^1rpAcePx8V5%$-ROV-kzq<4<4F$h4Jd*)jPK?nX7xvSnJ=~ja!u_ zU%OOnW_)Y1=l@sL^YZhjyPB)souYbWx@xV1=&HO^Yq!nI3Yej-`qAK&$(};h?YFWX zU2ogAop-CTJ&*JkM-$HW9VPQNEtwVk$fEZA#}$30wzqO_UCZiwTj9%ezxv2WVWFVk zwUO_>mzO7*Hf3DDq0TLnP`_o1+L5`g&TmSNZrkrJkZQrx~k0jrsw!Mp{iL8{#v~#-)=e2SB9&p7qy zN^x_>>s1*aOTVo0DzV)nc4XoGW$$f&viugB^#73l^Tsp(?(+IGU*}i6b(?F(_m@Hu z8^cath@LUYG}L67v*^}LU%8iJSGE=hs3?|N9X*zEDA>1bxAnC1t2s<;*Rq$Cai9Kq zBI~W)rgJq<9;KD3AFOt@&b2b>JGj)zZf11dg->_1Up=?|QPEZV#?PW-L+PE3rgBP8 z-tL!3>@2^tQr=BowP4m29ofFL$kw!TJ=;W?zwR;PIC=KKyn_k;tZ%MLS9|1feB)~I z+>re}BgZ?4{a(>-X3v^!YyaNLo0rO#owet2Z+`N1IiX*#9$uZra$mUq|APAMUtVNw z@Vg_GBP2fmacp^(cu%g{mM{)xkGM+ze=PfT=R5BCdTy&Cd%~+;+u}RVl8}x8bGa2B+%g_qmCtjI)z>vbzSj3H420F6tt@L2}lq zJr^#??yHb4QRa(G(GqW0Z~ zwg~lh{yH`x!B=C?jh@ivZ`rQFhvvGSkT~^Y=BBt^J*jP1N(BtXT62=tF-vc&%D)k^ zSkW^vM8Td#dfQ~Fxp~4povW6!F8EWje$|tHj%_WACit>QnQl_`KCblcYQ^uoXJ@wO zG~HFOFUo&){gpucuDyv|p{-{H7cj9uY$?^?v-6D6zFWuV?s$@?^FZ)}1KqxhH@!5y z@a|A%`7@559k=!#(6m0dwYsq&P-FR`*^H{u(*yQN280+ev$ph{T{v6agxM$2O{d`;^Q>iT*C9Ox`)gu%$-jS!m7tcxLkXltab)c?Iq6b56;$ zoD}Z5ZF0Bn0w3Y?ZX6&3I2QPTD14O z&%Bn<&#!U0DCJp=oP5Bt&ga~46J%0YPHk~+XF0V+i77V!)Ry2AevN;n0+!89JK??D z=ka0zjms^!H*|W;JQfdfTh(Ep3}y~|$B%YB#MI?OD4 zF~MPGm`hoM(b|c(Vm(fo{PO}iLgdz7haDUmm-%FcG%j~>NCqqmJrWY?`|$oz!_d3? z>&t(iZ!TSL5&Zdk%>4VS4%*CNI~}sseJWG1s6nXe?rIqU=VQ$EA9(+NE%^O@dAt9O z=WnM=+D4i$(>jvHY!^JW=Gro=0B| z*jG{dZTh*w;;0E%cFvh*eR3 zaB11I3#Z-0U0UN9Cp}~{xb^D5LHU;M4x@!{c%Gljy+%r`$t=5A7si!zwi zt-I}kyhQG+JSD5M27>82zT#U;K3Y^?*2~D3I=En(?W86x`+F5HMf+lML=!ePb-1%E z=vy&s?%^nw8ne>-p(!%{g$Iv6+t_ga*_H{Nib@RKtnx~Gl+q3_tdQ_NG2^2BlpU^4 zhhvp*tlGQAylum;Cf`FbHm`j(UpX1JTowPS*KK=FyT?3R{E=AM=eZ^Y+~*&O6;&*4 z_`2+!obz%`xxQByGc{gR_Aq_M4~3M;BCtwfJ6& zJ4>)r;0ZPE#?Q+bpS3;QBWUJ)ATc$o&$_Xwe_Gd~+vgvsrD*1hd=R#Hkz~B~KxqKi zbw^WIMe*aM7dYpzFZy~fcINDjpZjf(#pMh6H9xhw5xkr~hW$Y4gg5UFf9T%$Phy7s z_4up$vv2P|x&Q8Rr#)2%N((w-AL*GF$TD0%$hniR$Ys~Z81_FqjX$x*urFuzoZG!( zhjA{~bw|xjdUDqp%Ox9LFF0cmYZ=CNvbRC5K$e5umT@QFj@Jc}G3-0@vW?EnQJ;5m z(bT_UE?+WC3S^&n#)%%x(A(DV+QCLx5oCaD!|Me})rTKi-N>KrvfcbZX@Gb2Ws!Bw zT1s+CGI9^og&JNv?1^n{h+(h!zVS#F^0X@ z#N4S!_Cxq0kWDYkSYp`Qdn*>ku#3($++Vw6>%~R?Z&#b|k=}b}&;QcJ|GAc*n`d}m z*r&<(S-~-zn|J$fKV4yMeC^rRuU|7?eOYGo^N2pH!=br`?yC;1dhmH(<5PX}&9@5J z%-E;%S~H)Xo7os8QzaDdv}xDwhx^5zm@M^pzC}ae8;5SWf>IOFMdUTn|ZNaXjcSkBqRdON?@1By_FxAqpn?um| zi5^Sz?1GO^k1fp*R6NzY(>T5ObpW^Kjk53?zUL&1UthYtvhR*SoYB>Z>ft93t^E6L z*$YX*!yb&A{TA!`mQD&uc_6AB#j0)eC x`DgK`&e>o72uf#p`OS*#uQN~$*^+s>-eu~OsuuaIHw+9644$rjF6*2UngHpz!D0Xa literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-3.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9810a028186cba6b1578637834e7a5842fef9aaa GIT binary patch literal 22771 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 BZ`c3; literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-4.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-4.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3c04bcf0fc93b0661a475aaa02b7f7821bb734 GIT binary patch literal 22017 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 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-5.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-5.png new file mode 100644 index 0000000000000000000000000000000000000000..1b2ebc3b1dd53819002152d9f8d77413bdefec79 GIT binary patch literal 10932 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�`%*@I>{#6$H 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 M)78&qol`;+0Ak{N+5i9m literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1.drawio b/doc/publican/html/images/content-updates/sync-subsurf-case1.drawio new file mode 100644 index 00000000..385c6fd7 --- /dev/null +++ b/doc/publican/html/images/content-updates/sync-subsurf-case1.drawio @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2-1.png b/doc/publican/html/images/content-updates/sync-subsurf-case2-1.png new file mode 100644 index 0000000000000000000000000000000000000000..25408cfcc4290ab9bb830824518b0a46cd1bd789 GIT binary patch literal 26210 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 bpI!d8_sP5e^D`M37#KWV{an^LB{Ts5gHhMH literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2-2.png b/doc/publican/html/images/content-updates/sync-subsurf-case2-2.png new file mode 100644 index 0000000000000000000000000000000000000000..63ea066cf2e69d339936f24f6900908606bbca55 GIT binary patch literal 25821 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMiGhJ(ugZlq1_lO&WRD&6h2cL4F4((#G6Mqxdx@v7 zEBh-(0Zs#%OHcMjFfc@3^>lFzskrraZgq`t=&%3hRg67vwQSq6RJYYkb4yd#>ZUc@ zn>@rFkDlhz?g;qMrnGMV(NlT~5J4Y*l+2 zr?FSnH%;y2pMMn}9$I)_zTh)yTlGEtxILG?JULUTc2@no<@3sUhc&yLBzV}GF9w!; zlw)WQNvg{%Cun z?rq+U4=nUbr1vE4zRq>g$25oSalL@r;y}fKLMBt~mWs|YL1~XN&Uss6k{6o3zVa*h zf?L^%3zrg%m-zZNXE(OVMHlg`SBhY*XvqB#RlvDx>BTgjE5|*O9-s5mKBTB4dJIw0#+i$fHy){SAKDN3%wDSk%GoCe7dF0$^L@p z-?m?0GGCT3FI(Qjk!ZAvw`HZi%xvDIsf^q^sDB3Vuz=) zP05L9Jz&c9=5ona&YI^6L`YRqbW<{4Zg3{(@ zt8R77?`kV-JMypd!^8X=Hy->tA$lY9_4_E{-|9_PKmPtZV76=Du4~L|IsXc6@J(QL z4RpA+kazxJbv|#F>0&<2D?{0|CzZGfUw*#yaDM%@W$WY2L)1NmJj&J|uWG#Rv;Cok z-p6k)_Y>o9-7)#D{_a|T^vi=B;T)4x8jJ4+-4yz=P2F}DOYWB{+nTv69u)t4a`WUQ zl|<(K_uqf5N<7K5|K5yAMpit>i(Z*BUSX8+kDRtQZvFMwt<|e9zdZ2!^6RfH0`t$S zdrn$?OZD`o^Us?#Ezf^uYd)A_#M#7fdg43gycvDk4g!ybKP$E zbS5a5XP8Lv$QK$eeChaiU&pMV(cu8w%Lt6X>nyty+Vu1A2r377gd@MDsV8}5qqAu{QmpvUoUFz6^)gb z(VueM}GHrTntUTw}S10wRhcq`7a`J2R^^3 zZ+yI1qif&#d+I;`#MuX)`}gflT;;k2DVlRm2u>`B<5TI}x9DKjh3{9rCmrdOnaJ_{ zsl)ohMO^$XF^&^O_P+>MX|1>&&wE6C)i2IlLi6)in_sd1_3weMljPF)MekRe_nQB# zv3q!(Nzr9m>IU!SmsRi2yz{tEt}#pRv=PUm`|qC@|9E0OIq>Ymrx~m@@^d1$O-ub% zX2_fB!ZbNhccRRsb^UyH8!h}cvdc z7djoXx=%~i%;>t{#DAEh#O$DE+w(+&4=TdJZpRahR!MICeq~$8HkJD`?|kOBb+q_! zc+G##U&j1=Q?jmcZgS;tw0%@57w5XYQLf-3gRON=^R32Q2My-+uKn!WHYc1}vE&A) zRqYMA&`D*n%(oZFuzx!o*sz!3pIN}i%%#iri+&LLa-Bbp&#Ey&=R-&6t}`Z6E+)?C z$!cDtp*vM~le68{M^j#A1v@1+Wj*AV)hkh9b#&OtXzAe3JC(K8;nvM1OWD8heQlb? zBO|?K;qQZ|FFsxvF1JAbDj!d+?l0*kF~>i73vMsi?Pc9rB0a^xzV(&2#s}#Yx<~o< z=>AyBl<2R;*!%rH-{RAUQ$ng8++S##oqNGJVXA|s<4WG;yjoMVp1WV=&pH0sNcDU1 zhbS%Iz^w=KnAf-RK6v_N2J`iZgP|c`otJN4#Ffk(;;@BVbiSO#-?IyM>3+G&Yvz2c zSdw$U=YdjYHszujJ#JhzF)vRjUU%1f$i3qBHyGD!b_|o~^W$BeK;ocWQ{c5Iao?r5Q_44v{PHWZ~NhBUh z31Kz}5UKm}v*v?i=vg;r`_+!2Y`=4|*&|iO6mPX;i1ih0xvlnz?IBO-RSTEBOn(et ztYzaD5m#aokG>_V)hsBYw)mFv^-}_^%)70&+;2JJw(!xVHHTwMBTgKuR9rXnka%>$ z1cv5|i4l7Pa~H&_+*g!8*1JiT=j=l!i{;|;V(KoH-*7+9f8@4;+w}I6E7F#n_4TeY z=@dBh^R&$6DLo~EXzgU#%-&pxY&UT-_=w)gT0kHn>O-j%m4 z2>kZ1EVFuMPZryn-IBR(8r6*p{U-jf)|N% zIh9rNp!wC;DsOM^@bz(TORNrO=5LJf^749iem;Mse{5gIZSHsJm(MM0Ud;DtXU)6% zBE#oflk)@Aw{PEkaqru=Mn+a2j_EJH^!eLqlZk<@fp^&N?y|F5f1TUtR@k{zi=5lr za<8q4yn6NObE`>z{`@h`zSbjaZ6@_ytLn&sxF4&s?_K3Fn)Nr;EXC?zcx+F%&BpKB zXWu-X5@Ia*H|qb^${m(3&n=mJ+W*`A+woJ6iu`lmvSv-ryE{7@&wsaH|G$BoJtZ|= zRb|GVyz?IyAOHUTZvBJf%#FI?>tZa^&&|oWvo1qGy4ulgcA44LnDE2TKSlnZezZ_V z8+SI8R&oBAvHQS=} zQ19csEzcsEZ(C={+}@s3Uwc^ktNQDgezRuH3R@Q=`F{7Mmv34xsZ>1kdQ;2s?O&O9 z_1A83{l4!Kx1L{_r~2}_Z@<_1Q2k~6*B>9W(h1J6G_s&{=H>h{?6*nuZs zE=-v^RX1`|OWm_~Gt2F_f843v7CY~fvFZ!&psHm&d$V3V`Mu0z(wDE|@sB^xuldw@ zGDS;Ar{|dO7CKGp>5|y&{N1Zu!M`;=Oy7mLUoRMS?#ee`Qh9sp_u+E;m>H%TAL5_3?^fPu9@p~upB10g zGaHlVyB03iKPzkVYSZg9dxPDt+OsooEwp;R*zcj4VrJ>2 zlPN|seJWl=N6UvyKRtEo)YgwB<>&Y8PC2N&%Isa(_xyFc_b%JjR%fKF{dn%F?UREi zh4zN)R~Oyg{QAMhqe+%^e=3%DrSKiUcewAc@G+m9oF6wiSDw^7ng71ZdULtk@i(oR zj-S`1)%L}m5Zw?KwK{pYnj*VfW%w+xOq)KvU1I0myzRH&Zrl_8@W$^) z^W$@JGJIan+*FwTGyS*y-0d}bic3~*e7Se~{q76*`s=@b-0${Jo9$Jl-?wch^DXVF ze(&G*_D_}iKkh3R-hKS{uk^B5dUx>h%YVNf-hS`i&+Yr`eoXUQ{&|OOwAp`Mr|QQ} z?5SUVKA%6|vUr(_C%@f~1V_h%ZM@RQ`sMvOempSR;-TmJsPWv8ZSCLinh`Qb3X zd#_aKt1FsLCvNBOul@h`ySa%;kF52#D=UNfZNFT2c6RpT+hYueU4-z>x>+!HPt zZ0Bcq-l+Y*mO+Wq;{r;yt#FRIB@bGwV_{ds)os=l4!k530ZPkIV3_q8cz z+AQ%z<=2O|u|G~6ntk%@dAUll*ZD^i%*6WkDlFb}V7Bht-;sA8{LRhFQfpCBRd0NM zbNzz&pdul~B}-TCJpAq0M7~omuC0ycRMg-9=aaC%&Bo&A=M0mNsi>-&nwaeQ|L^xC zm8nyv*!=x+dA51}JlpDT6BM1ly}$3zQTcRgIEUi;z29!l&foX*jPZE^r?NLU1oJ;{ zZL~Y(B)}3pkMrA$!<|bCcgB>|ee8Xl$8+n=zx%%RAGdDhKK1Nye|vWSmR(Vaaq?Si z@A|vCww`{vsDAaYhR`q&IQA^AHS>LG^7`2ZU&}rmjhYqp@6#3Uy8ZFzU%U57-b}3i z{q^e*7WITXWr_HSbTc5E(R+x_&kG$E(3wNX=N&8m9X zD!%Xkzu#Xz&o;}|($SHztNHP`-@Z@(=kNRf`}*zw|0#Cz$ji&ybM`uq%_5LYGcI+@{XPF$-b5|3RmHR4_K$?3%EdVqk8=@J~w_r=ia#W;nPyBX4`p{&O5Y4e9wky z%ck+_=QO16`}61Y?!4XEm%oMU?|9L4;%%>F;w|fE&o17t-(3DUK5lNsUs=m-a}M_% zW?Q_lqUz($mqkvK7r6t+x z_m=(t_gC4y@64Gqd!Em$uKV$j{c1L-s8~L)N=sS!@xpewuI)di8ZLg_ci8U6e^Ut_ zx5XC|3@$9Zo4a?187 zDtVXcEcs=7H|a!A($TaHp0*}#(`$R{>Hl|zEWhkI>C2l{&y_ZAzr1h1%<b0LVs*XHt%irA03!TWx^@t*6q zeL>E_-10wGF3G#LpPg;a9;>|h_FM01IuDah*nYnwyl-#I1pa^T1;b zldONfqi0P|wE7*ZKjDWDs=uA~{(biPJz-YMzdY%jtiNyDx7D-sJ^7i(8`=Tc&o=%UidvJg;;#a81(`U2u@9ijjd~vaR z`k5II%XZJN`;}R7a#QMQF})azj0+3u|Np+f|Ho1NN4dMFb(95`omkf&0~!J;T$LFt z{3mqlZ>Rp_&Ub@?JEnbAf4%%}+4cV4tImjhzAQa&o<*+Hi+L~aIZY|=QC|4A^>dgn z=dv|#*6fzwll|doGpFMFyqnj0-!475@tbPP7OUvpOZVpQ{T1$XV#A`u@c8Pjng>gs ze$aOBk#gj?`Rm!Wf~v*#rgIznPGr>9?me4!`sB&XoE(*wCCiq@)qFgF!Z}&Zca~u?+wsEkJB93uEMBpyYHIh&@7F#)-Y;)o_eZ(k=2GM8 za=#B-sw|=;&6-|Z-M%eu#>B$1)qj6ne4J}q{q$$}zMrq8old+ty8rx%GZvxcT>n-w zUCDfLPtA8$NO17xjEhR4(h=6dNheP0@4vHdZ&lp+LF2?5*;}KYpPhaE!i9oQPfku&_ct>!*%71XvGKU;r5m@sIac2K{&?Ei z`rpMjgXKeOuH3k=BlYuryPID*6;qCs=B~>uyZe2*z$E((4FaFu`~Rzb6d`+Ni{1Yp z#ZDfM($O8O?!EB$O<&MF`B&-dYr1iJEDQ}lo;AP!=hf=o=<;}&CPZ0-(80f?g0immGAPO$9?V={E`2w#f&@t;$Be^ksCSN zj&_T$w#(U2Hf{R!?R9^D-MF*b;O*SaIetz_O}nrDy`9P5zvIWPN`Cui-+v3A?fm}l z+dYprr4};UVQY5$c+`Er=JVMCGlt}}_h;PG)t0MN-UCM$ z8j}w{x$6rL&X(UJ`D4%GV}*yOrYA3)$0GVq?QI9B0izZQ72oz%#hY`!g&1SD8!g+k34pY!{FFlW%38zHk3u`8Ry;1~1|2$9$_lEMb&6&Kah- z(BPoWK_8BbU$1h8b0|)F5!xed&L_Wr-$UNWzAYj%bgJX;e{j3-FS9_3gEP%gx$m1^ z%#IK5pS<5}KiBv8i<0E(|I6>)w>Xp%BHd$_e6HG(vz60n-GonWUj6D-E%SrpV`6$f zFZeb2tN&D6(T551w5qwzCv1q&IePS{qSWy-{x4O&rA^M^2xz`KLqaEO<9G9E-;S}W zExzS&ow;q!uMhsq4Q8KJRaO1*cvt%Mx4(|BFJq1oAKzyxT=$` zqV9sWwyE#)zi*qKYnWNq!7(S8-{By)#VhtNB1PMsudscq+WUNdy= zwU7Vz{Gau^=eRjzU7IQds?`uWE4w*G^PN^kzYz4y&1 zKZN;#@C(}~tanZRxcvBfwQ^qk<}}`aFLDa+)*t`-{Fm&$*Ydkx?6-6}G0QaD>f!wu znYX+Td&|75A0PccYww$s3m*P#u7!WrT`!k89=UGgoT$Q6Gty0#NGZ%~^Sj1(@qFd; zx#>nT3%Y|RJ^6mG^8Vv*JbSY=R4Q5=rtPhd`nde*=P-{+J^t%rc7A%d`+eUr-^(pK zZoK~f`?c3=4#j8HXJdrejoEr!yI++FSJ&^}xYx&Rt7XE?owqBi4re-b#DBd0cj3AF zPyBajaQ;A|M6>W`2C{oyNs*SS!^d?3w(Uz&!=bi?SK6C z*S23ef4*_L-}CzPE@;jebf1UFG`p=oXIXEoLto+@b1J8fYzg~Z!m3h;q%|b#xdE1}=xcK<@_jkv+ zdQ7y#*R@=^t>>8YrgdxJ`s=S(mF?u;@pb=|!*_(eq>d@f)jamCOzxlfn^dD!XT>Hj zKek!FUVi@RXtgLQ`Fs<9lXRQejJL%T=LP$3&b_@Ya&y|nbnQ0Jy1IX$Sa=?J@8eeS zdulez<%-H4@-}_fFf&|YxOsc<#kZiL9jU$NOeY3@cl^%JYX4zp&7-%SXZ=m0WRiOgS^(et+@0gU9dQJJ7&ov0TB-`s+r}aM9Vf zy{TWP=W*5;Mc3v0oK*9(^xXCPf1mBvKRNxr{lD7W+_xVeAD5PvzMHpQ=kyoJtcQ9(?CjMVT>*A#UZV3J zW#p?b*?sG_>7I+{cxvpT`M3PDc;H^!7q`Rd!=9&}Ka!muz3p^cY^bQnD07M9uk7^G zThq_aTeWJ{u3c9B$CHg_8W|aJadENn%iZBzJW-kb?cF_<#jdVLCn!2U;JM}TrgeXX zfA8|j@ZwWXrp%ZdEU#Z}ZG895`vr)az2yQzsuyFuh>3>iX-$ zH`k=EXs}M(d^0O6OX&?)N=g3zy^~_4K0Ibn{C=i9I(@>$j2ovrBz6A8F+XsgVW)4K z88oS~Y3K9fwm)U;E}VU-B7a4X<=BoJZ@=w+x66C7-NplEE3)?Z_Uzi*BXMBQMUO^* z5>6F#Xk(%-(_*S3CASN&UZ4co4J8REf!oP7wyfBbAO=oc&Grr>D&e@m=l>n@eKN2GhV?d@4{Xip$-!}-LkC$ygD zsVl0~##OC9UNtv3R;aCOTV8m(tjQO*)!nP2?epILP0iPs!oGFKqkZ2N?cCcFacEEA z+lybXUYzH*r~UF*hwDA-?${+A;qaB&axc63dEI2~CtP#WrwN2sOByzuTw!)W*!dwB zxy^l=WM@SmOl64mX}TsCQkbjc`$gnUn~36sZ(X&&3tUJ_-w`&$%B7;d^`78 z+&bOC>*J=(s_L_0o~6u{`7hfai93ehe>8Wyn9KCrxdMwK*>ANR%iG>O>qgGD%*)Fj zepYttVPMaFb!BDQ?!C@qE-C51ON^rE+a&K)Zbg?(-WAVz&75ytG5Is6yKG}!?cOI7GUBf$n5O8S zak}1_*PL!Gozr&ZQAntC^I3=eN2g`$xXqq8@BE<(4#k>xGo=Jpv29t}_>4VQ`IhU8 z_Pk=hEY?Gbn{R#y?OGHP7IrIV8{hnkY=w*K_RDwQE1$Omk^(_KP5tuX(c<_!8L~t$g?l{A|GA!=EtSSjk)L6Tgj{Lu5+$^dw1)?+a)>gd`@?%y$|tD z_5Qr>SMh-<0cjpQN(?KL5qV z%WNj=oSxw{`EOF0cPh6>|M};iuT^m>9$VeBNQ0|sfd<$4&zh5iRoYoL*G-Xo{KGhR z!Hoi^M5Z}g{PcHng>x*@`1SXn@!6uLJv)!B?vd+f&k}w8wMsEuU`>`i=-IHFNpf|-C)ryE z=1Dw>ceKC2xrOm{hW&Ii-rEVTPoAAU+q*wor6uK$_2DV$hZ4&Zeyw@CM6UQ%@x9ZY zGSfWP_m)knw4HsW+;xWeD#;Z(3#Jx?)IM-4cp=|-VD6U#=SA&03uM~$m(;U3{BwAp zVLv^Op@@fd!i$wwW(*4&{gyA*_uYO({7^aDi=vuR#SA}NixX!QQ(ZVF2j({TEB~1E zfx*`Lhu~L{D`Ix%KQuhHI3v^AZ^HKUK=K>m{?bLa8}d7H4{Se_{-Nl{DuG-FN#_5bglqdA8(J_C>l)5y%8{xa z;PcVFXAh_1@devTLp)I+C}gQ!C@UYjgFozQu&3@`riR=N^A{A!Y>~HG zA`|bl{bJyjtNsbn0%sS*^M8<#u~OJ-akXM<;Ive~^QGG!={T)Zuuh4+KYy<~kDJN{ zT{T_KT^*bkl$_RkU)t|#%Qfr1q(s%qQzDC&PR?6gw1a7}1@rH~mvs*sn)x`V2ked0 z&x!t7WA~wKV@>IvZ8Hq^Tn~LaNu~3P+5@}8-@>1-Tzz)ij9p4+q_0jAnD6}Sv0#)} z#z(HZ^)qst;=1cL-L2aoJXMChw&ykfhBI8=TrX}M6Yuc8eA24J={3*E1wDBTlLOy! z{@vK~#98`W_Te}C@21ISG@QRs9kwCqg6Aux$FEpwS$w-QO=r#EPmd=ILGd`LC_1+zR6hlBcQ;8Swpi)sQmX;r?SgIk)c(CpDan znHF;=oR%|tp~$DRuTGwiU&$?!OW0X>MvsxnvEauCk8jfHUc|9_!rVk-c2&7Wn_jGl zFk7EqBB8dJM>mkwuk_ZODhY|xE7LQWelsU!@aRt8=WMsa^OoeRUbbgfk}rmey*}5$ z0#+rK$-Y}zvr#_%x#g017q2Exu48@a_2tQlrVvtMNvf0!`)PB_1@f5ySskYdA{oAzE$dgG&KT6Cxm@;Ld>I^lO^hFK< zf+7Fj^H^KzET1RH3)VL2#lkkt6B+83f^k!W{ZDIvR%#r%@0d^`?a&`1zw^!FxAW>N zrR4Kfj&tl<^f6RB^rnc#pH-7zSTA0Ecu!zk+JU~_;_a7r-qyV3dQ-kf{< zu2AOsufpul>z+-~)O1>RK{9KZ!7j!#(y1AodG*{onVwv~oPM*sZSF_o=U1##md)l_ zn_zV6g2X{B0VkDqmQ`Ku4&{@A`_Ih@&KD0YTs${1r$>)#_7&qTE=#@Y_Rl}Jvj2Bl zZM5ZAogbZooIY-nQHy5n{QbAibJB+ufmb&MZj_I>FsF(`J;CVI3j-fFNh#;k8grDc zuT1;0$=NMmg!{qq>X@E&ywTFB89Yy}M9XayaN1!Pqkc0oi1F9GO0#_uu~N@^jZBUe z^|BVdIw`OyMYALzFx_DT*CyvMQJ+MwQ;_I7=%YCAxo@SK#qxc@t~;Oana=$D%4P3G za}yJK)^Se`Y@2q$@@v4gVAaKi_sX~!ocl{R0uW5v8=vOpZ~ug<;v@?)22;Z7q|D; z%aXQY#qOg)K|x0K|7zy(m%FhhXWzT}X645V&#xR$71m(`nKymn#YXcw$*J?U#~(`x zaTakclrMRI`aZjn7l&qsR)ehihu=-7UTn*~opyFsXl!ily6LCSpO4?1cJ{``fZd1=IVVG54Zhmxk`{F;m`E*En-}YHDin^K-m! z*8Z>j%N}E)plz+Kc<@PCb)UTLzWVq7nC;~j+zts3zh83MS37*&9OLwJmb_PkAA4%} zTzGj-Mpek0x3?SA8U*Er5|iIEl@u18@QjJByMJeA@##~iUdUalTIxH;>fy0M^Qg~j z8vkOShduY<0pqhPpKbV0$<5xdT;lfW4qlz^&V_~nO6Q|rv*vOIK3utGjn7g|&;(tQ z|Iy}tJBg5B4#jIWubcbrA~r66^loN(`#Y~zt>yQge?GaX$MsKAae7jwzVb8!$XU8WeopXCz@4VYlRWs(_{7`bT$(?24U&%=dA5^*JD$@>Mo+g)WzW({S zxw~_3Z!>6jKb?{D$?b}W0lS}*M zrrQ3Hu`BT0vSrJZd&~8zm%W*ES}$|;dH(JHKOb7-D4xbUtLC%F)%AKi-%Q$+e(qfE z>eZ{gy}b`hruP)Ty1ljhm+bfE-c|LN-|vVQu9ggJJ*nZGY!G}R!&oZU&BC(p982lW znAPFyk9{jYzsI^I{@R@@F;?bNf?}+HMOED``19u#`d~US69~Kh0N@HJ=-7ltZ{zRQu$oGCFAplIqjFLmL5!AemOEOPA;k9_|C`bCF)5t z_lWfE_2080>-+YpKh`Imw=d4IY?+X#-0ljBl9B+o`St&P&NNQAWA`Zs#xenQ4@EW(L3gpMonZ0+;*EZTkMZ*Zkg(v-x$x`I99t zGTB<6SjjGFI@5=(*-_w}+~J+6r^RYc9$6{u^k!qtw~Oid`~Q9Wuqe@a-42~2rQmr! zrhgva{gb!f_V)JH-|?X7xP1Mb|D6&c>YT^#EqSu!OHaw4?O)ICm)|7+sy^<&XZhWW ziPe&Zi<^yhmA(#hI&oTm|DPkm{%`K=EIu>C(9_eCmzVeb{{Q<_JXKXy{q6sLd3JVo z`uTabDJLfU{rz3oiHnaMf_UsMFHY3i%wf`|iG!lav1a{jDFnYl^_9lj`$p z{{4LZ#q#UL-O_r~yU$JMPt-5EQCRVI{xu<|XF9VNKW`3y#-FRNe5}OakDamcWPwdt zS65xRa)n!e&xgO??=PQ!e@kX?V&cOO4-d=N|0%3FS^NF&_4V=l7dp3pdv#U&UYPMB z@59H~ZYo+Iv*1vC_AqVn*^YN|drw^czvo}>QEwrqe|tWiZ_n=kllW48)9;6ts^?q?|U)B5~uSU_^8Pnf$-;aCp@#t!oev2=sPOsbb z>{RjA>4M@`KWz6T9AsL3_1C-I@A;%mH0qy#^76J!@SLm`Tm5$H@9*#BEsIjp z(w^CVzw`Mpzx@I4v~zPR|9-uG{C1q1&I0p&wx)7cc~kCfkSloDu&wIH`|JN}zb^G{ z){`uGZaewV9*w)vp`lan=Ed)+D2$7fTf5L~cCOXTe|?|lYHwP1K(%AVxfd^Ql`Fn+ z{rCB3z1F?;3N2?eW)}K=b34!Cw!0+2?epi)-{0NcUH0~tbl#4KCnhQ{UAok{oi8^l z%SftMR8%y2d){1|%1wUDqqpbXeQ>aO|BpxA6|+xv$aXDqP!fJ%`9jcDPf5536~4K!}U4;@390=QmtkY*>L-<{v>gI<>^afr%#(OA;D-Si(|ml zDc7b|zuUPywmLJe@}H>F3D*5P9(+1<`tbJc>(=R&oRfafQY(5ly5rN_ z!X>)Z6Ms$qYW;s>w}8>JXBVGek**Dw+_+rXC@MZafAh_vq9Q42X->tJD_4rg*BFW% z-23m>YhfWFyWek&ojA^a-Vi5zRkgvdE9ck1o8mKVphtNmqG zH`l)lGgow(_Eh-ztEkwuj`6PF!$Lwt-p{^xj-z=~@o~TX=lwZ;Ugh0ywfvrsTJY|- zk{1^%NBd-EX12Dr&Nj>4^ ztAJ~uk&)4d@Z-kt zHBay9x0ABPDQ8NI_CB9qt#)tTiO)7|TisR`eco02x*+cUw7n<9=hu32oIG)A!?)~u z^{#il`&Redxa??Ocz0K6x46Eak5A3#v*!DMy;>cew=?zny4bzd-}imLS8bkqtK=Z7 z_@3|gs;$f3NSI_?xVARhy zS+>9KUwFW`1G|E61qBqC6)uRaUj02>*eU04uIvW$Dm8;!OPd+}*_snCE^_@MuK}9c z_MF`GX5GKf^Z)m3-`Mk_>E4`+X@PElf2cO`E^1tzfsq1i=#)6igmL_U7NqAe$|_m9QxlwZU$EzYde~x zsi&8>da2*?%{OzZ_Rf1=X(eg0%1g?Q_gy&hW(U#*0rVo-s z@4T3KAP7AFu&r?0j(7VX|117_vFvZM_*%`D38vZCTCRya&wJjPs@`{}e970xVOFWe zx6D=Iz8NJkgE|K*&aFMHv+TfO$K!pn-tvNPatdutzHVPV-B$7(Uyn|8xPJAgg)8?j zHBEhbYHITFzTEPP4-Q+pH`;V-!i@N~A|*t`^#psUY^qKAxjB}_&n}!_Q(YE&@xh|! z^D52-KIXW!dGWE2cZAQ2^6D+R&fZ)mYN2wK@pRn!>2{JPY)MkyppncM>N47X zs@nUT>sw{^-WGww7R{+sk7k%8xvE~hD4Uv^`sL(dkN=;4@$V>b2rCP7YC8G$n~Z%` z&HsCUOU_tsDtdaV%#@Yw+Lp~PAFOC@nXqN~WgTJN4e|Wdz8h!WJ$?o>R?Ds3^PP91UU+n*;dUbu0~ zbV1`?Jw5+6{59gON<7l_#Co!HeC`+7PcMJHxMh31;?0eX$;Wy$b#-I+R+-NGCng2! zto-SFyYYu+lD%U0-n~65E}5!*?ODg9p|+;I%0@1I>gD+_)mt7cxtCzjV$py3Y0=c_ z)AMg`Qgu0aVbP*Rg^!Pkii^(=-lJl1bX`{X)dN~i9+xJ2a_;vOU}4Kdp<;H^N7JYs) zR_X_vrkTxNyKI@-p~jzo>pJ!cxn6wzRjW&=xoUCGf7XZt!p`0s5+<#(@?>Y3BCx6A zV^T%J_S^4wyV;LJ0#XpS6E; zb96h%*(!Repo*i!wb4W7(g7Vcp1nz*tK3vTMyNL0&AtDAda9(Bji!jAm1FpoH0x@& zXB~pdO64Azl1H;N4YfZVd9e=EBkIZe)nobfp?Hu}_!PUUvR7ADeo$~~7m-_`WpniR zJi}dPK5mkM2W|fNyz4ET^Knkesl4sYRkx4^+}lf_1Mbd?+8L$epR2s%af{xtBd~4S zf%(E}&AaaAX)I~E`FdgTD?tIT*=O6%iny*^vu4Z9oG(8A=deBd{Bu^B*-iJ`oQj$A zm%aS`O40g2iqTQ+Cv&>O;t6Fp8}M$;DCGBRJG3UyvZfGpeU9&@#DxA@0*I{ zZCkw0ys$U=+p$RFX7=Wn#jhT(d*7qS``JxW>hjFXdX9Ib&CM=7zjFL{o8c}S(0C5N zZ0E|?i(m6(PS+}I@2Y%ZJwN!Y2%9tODcdWhP$*t!Ts=!$iD4N&pVDhs)Qo zXUuONy?^U3OJ~vZK#OrrP&t_F8R1Gx@R3P*bkZ0H&i!2KYp}4MB$x_$_wRkA@i9RmnIsW>fn0N zct|Vdxh7N7^DB>Mex0l6I`!h!#AqL$w+}7OeVusP?$*6MJ0(-P*D(m`pLLRt6kusS z$YA+Z=T@hn6!|DCbi8nqv(?T&DSuB@&3hjD{L1m#ik@}c zpiwV&Wy98(gYUmD7M8lNRoS)3qTJeF$C@#H&W!fiGpmeD8Y>s`=pMXM%29It>s7~F zsdpCNdH8CRbDR8M`-4gEB_|%<6Zn?%*G8T%RUv1acDV*-3ExKA=_5` z@|-=ZEx7d8Q-g`qWrU`bf2!JRbH1Ey|NC_26Ka!G4vGnXc9Rr5loDb*tK3vRy2z)< zV^x3Z|N3v{w|W%J7scA_`(lw+rfjMI+#&a|K<=-7SHyomv^ZBc-S$tN!{dfCtTQu% zFK_TI4cxj){-D-{+*jsTuHTE5&R8FzoThhz#sBixiL0|xLMP0gRGaoo=Dm6QijzSgsYx`PwFZU@~gsyh7gfLX6-@7rybUr%XH z(4Fh|{MQN5EoV=bs&Dj-{#(IUwI@!0%fvT93&c+IMcxnZ&uxiOTyfGMvHgO#-E{Fa zOzUize#z`z*T2sA$y#X;rZuEzABg98rCU0!=4pa zJmhkmmTGZ-t*&R&;|@iZO!?4+>^;{nT%{?vQ!uTVp4` zY~5#@{#+5)kN;S<1@^LY-8{G zy8JHvOqs9e{QUcGPWJ>h-aNJWht++(nEs1|a4zZ1J6tF;|FE$BM^C$5yiYn0Url`O zZd!d*w=~rALcyBDAN*gax0G`_`FNM9U({TDc7~CqtBC85suwDns~|Hn2V`@1hJCBr zyUWh1V@adB22S-WZPK&9@w%PkQ~eD)b2d33)G` zEz9={eeit2n{&`CLrN|F(bGqzIvTcVCcN@Te(QH!+?r^#O7-{o+xii$b@#s>uGEWV zVxI4KmTOMNO3?OKX{o2gtOF?_#tJJq%BCf-vz4;^XFth&Um)$i z*8GWL@lo3{Y!}7G<~Ua`TP11YHT#tKGTGY>M?)<8za)C?uyCl}_eCLaUvt&9LYH+@ zUthoO&A0M9_uiMk4}eOA11TZQA=%xNVjmS(ToJhuZRmX^lf29KPHETU9c`c5c3rY^^7yr{R9Va;Bkub6CU8<)TH*rc5bpG$sbMrr?yiJPP{cg^M3U$4ntTNXZB z;mVcw->b9t-gCYuSN^3z&Z6(L+$SggXAjeA#c!p8WfEyYJS$x}v%Lwl0TLR@SPsX}e!6>OPZZd`x2HqyLKh zU8kS%Y?o|_=U%W=;28hx-x7OOJSS=WFxgjr=_zEN+pCw46}(@(YZ_3v*=^>%e_eHH%wPBFiY27I3!`xlW{q7Htx)(ht?6pdA0{;z%dq92uV z75Pib8H)7`KguLOPW;OIZSJ@E+vf{hdi^;r#;pD4dyW>j#J1hH-_||qRG(M>uX6fn z(Q^_yVyEBNecxUA`Psom>T@UY*Cu@v!# zBO9q#(vEpTY9b3Q>e7GlrHE{D-6+O6_c6;~&?dWYZ*H>l%h_B{eDeJH`nbKn+NARi zs8r3_zNjbZ8(+uoMs7X(DO*}$i*Gc8$sG2d-G&Bl%Jht3hK#zzsp#E z=k?dFMI7;^0ke)|m?W`^sV(m5JE-<`7NhjjdChXQeR7*-yzuzl*2{aL=lny%>%x1T ztUmnvcwD~z&Bo(Qzt5kPpHY7B=-y4mJ)E73c7J_x(fQl^{VUi0Ys?FdjjcVcyM0Z> z#z)`x|F?a$DJycqyzA1r$9kR{r9_(bnqT~Tr0Dcg*bcwvVsqAS+Wzc!e%9(bv2&p5 zsms3RYh!j6ottC1@V?Y9Z5Efwe(QRBm-f8lnjEORQg78X*-e!@ZhqsB4tRge=3>un zuSUz4EfbE*Rj*mIrl-!+YyBDNcXR5_>XxTG7cG!+ue%VM^J?7v4#{3FirP1|! z!S4@y+pGVs6>kwcSR&+IaH!qpg1+?k1B-*@Vvlh%aZZbDsYtDSyy|CtZJp@fCtaf2 zPQNpDa4{ZaZV^}$Dm8oSMThF+=V#camTBs9ER2`9a_@qj<{rm+QvQE`Rk;RUdcJh^ zD}DpX)Dj7^xfgkU*;w!5GO~#ekGlS=aP{ZX^ytzL+j4KaWqU1B&3w3PZTZ>X%J~Kp z8op^&IPS>4CojJ4_N)xgL+a1Z&fZ@8yKEir3ooTDRmXCcFZHdyefh$+H*>Aa-)+mi z?X-uhDEGD3YpM9$luIWs2&gTV5|EhOAv%3yn9YN#yRP992cPead%q@f^M~Uu-j^`pTT;ZL>)nYj%J2N|@Yd%Xn7dBmg?IF~dBN(> zv-J15Pe?n~TPb?d|=t_LckmTNVE%Xfx{< z?)moMeZF*Ea^JgSGINvvmpAgBlP`L@*gyA(JY>qtx#wre&zEhV*p5rMUtXpr5uK3x zCqrP_UhC~SH9vkS?my>0$7spp%@_q11^H?&o+zGyN>??UG8 zz^$_`_Fi;wYu4L)(eGdrE4M{o^@B$CN4Ys73+-D<{A}$wue#N=*Q`pO#i980=~Ic~ zd6%?{PrXt2cV+whcU4vAnAw^??&2)pZaqVDvv+XS+?8$5ORP?xK7Cv2vn0ROYyqdJ z)zKd>>{{Vhad_kQe?KPnt`-w=a=Tl1UHbl2`)|{AWscvh|MC90{GYwd-`KcRbJi?e zdeLC=$NkN0MplW3S~!K(M8w2|oHlLV{O~xp{+h3L&%1xQZngcrZ_{)-Ij70->r|hb zbm#Lb!~Jnv{@q=E@BgdmuI6P2;-)?n=#u|Ydn}=Zhxd_NeEr{2rxVui_k2F7K0l`F z<Vq6<%rE>DX&o_?cdtaVWat(~p6Q65u z_vo6Z<8S$rr>4_+euw^eELr$^iLbw2<8e_@QP5nM!}i;6UteDzzpLcs^e5g*X!~3ORvX%G&2@sImUlc(rfSaZ+<^(z4|A~{n}UcE42FCn}f%9vOZ_;wN!8U zQ1d&{!Q^HoD@Y*jXx?`HxIH`K_t$w(*E@Ru+Q-rsfs=|4C*^&47c}GBJc}IlmL=cc z{XQ0adig)2@6+m*{VzX!!FKom!gb$P-COYF!ulcOEBjWJK3wuLDLmL~OJ$Ks!+{s~=HA;Q$$j?X9hW?-Yc*@W&#&TFbl!IMuG_PDw^dDK7IH-xl2TBA$Qu-L}njz8)yCuxrW|9w(3e z+b%Sv8aw00eMZnKr4?)kL?rtEJSnaW zHBl0&|0MhEXaA4T%;{>EZ(j0Rv^x~!Em2X?qrcU*8as*p)tB<&$h4^Zlhe|y(sp0E zHazo5)Xytj!Sm`XHyqRc>?S!;I94)tOUA`NKR+kF|JSX*Z-#ySzs=|Er1K{)Zqkwz z*)-$DiG|GjtpbW;ecyiF%FZskq(AWVi4zC>{N!wxJe+{KyJz)PtNeR=jvYJp3k=%Y z+NMnt+kV^kcu3ai)B5{m`t}~q-!=E~j^N{b`@bz;nwNe$e5&=o&mZkM6`9%NZ(j3$ zaqq?Mt^~io7k~E~sZUv`crjKwc3+L<95t5N%d5Y=+4o14>pZ~7ncPlHuuv5y%GbN?>WEX#_nkTU7U-53g z_53xQccUF08_%Xi@2U8>CG+yN_3{0?eHP0uj*t9!ie1|7$Kmz=44%z2jJRl7^(!c# zpe)<2W$$0TJx`83V&9%yQFeK9?q08Uu*>DXR@JI*-sk=$Tvlhsro(R}CN7@Y zbFb?4+Q!?v6<@iOs6V)@VR?>2b&6VJv5P`ONNKu)jc^KR_U!2M?A707*RJG}VpiF< z>s7z}!ubcAW;>Q&?Y|asQM8YpUyg@A!|?95l-ngnwH%V4-c2n3Z1&{p_m$^o%wMR* zxb)}VLlaxJO&9od;FA6KZC~$ie5rq2hF$2)wC?qCmS6c#8~=)GHp@GGZ`(cn$Z3gl zr~F*fb0X3D>qH?5#U&bC^Y(E*SROKe@psuzmaFG*{uNqKQJj?Y=)^?j@^^PQdA07} zw8^}-=)mfj>f2AU^JmNaTcLITW>0^2S69f!7iP0_FD`N|pHtrc*-u?D<&6HZ3Hj%r zuwJl>GO;n;d^08_q$N5o_og?;!;)Rm@BiLi`~9C@QT4~#h38kcmx@LtbY2&%>v_j` zJLwY7iCO9`FWUaS*^wNTqWJAz@rCA_ue%n3HpN)q-1m`ny^gzu(0ZNx`#(U-8~Psy zil~BS{f$aqTnKD-69ld1N|<>iLqNa!<#y&%)*I(kwW%3MUhP>UzUk6Dzt$;By#l*;Lk>oj+Vd8X4=*gAi z3liK53kzf3xK92lGtbV<)GN*CUwMMjDoM~l`kjl1jV>6R_Fvx#fflc1{j1&Ew>+ORkF%ANZS}!V9ju~a_Q!0_uaDf!_B*H4 zOn*+z-<`iQ{{Q=Mw{`OR{8F>W#@W}_G&UPJC+s;@@hq@R=hZ#tjoZbGU!6UC_SgIb zbt6NQ#*-_|66Q^M%{%>I0t4?-`xP^IxU5zSMLM0hu`&6ja#Qr&v)=FbJ)J6A&ymi4 zO#AfuH9rnt+MT};Hsi(nQLFjtgzvF&w}LZm!@e8X<~%B{hzee$tG98>_Pfe|X3Q{B zYLwlu<{;zgu0>lywuSVr5n9vqWG6lh z=X@`6aLZIJk}vsPW4F=m%JUa5fB84ge|X^X?Z!JzpFivE*b!dVXQ&uhvVERS)rx1o z^Iyy;R{7HTcFVGcNr%n}DY~q`-mERVdGV{{^FbDH2m(nIf+RSTTm zUamc{smJu=gOkkrtr#{g?K~`0eEℜ7d?Pq?wI(mT9(FY?nw;T~il_FJxnl)A^@` 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 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2-3.png b/doc/publican/html/images/content-updates/sync-subsurf-case2-3.png new file mode 100644 index 0000000000000000000000000000000000000000..3948988d51cf3f2f671bdfe53e81f9b6d1ba1ec3 GIT binary patch literal 10069 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 I&MBb@0KaK6BLDyZ literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2.drawio b/doc/publican/html/images/content-updates/sync-subsurf-case2.drawio new file mode 100644 index 00000000..c1eaff66 --- /dev/null +++ b/doc/publican/html/images/content-updates/sync-subsurf-case2.drawio @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf-1.png b/doc/publican/html/images/content-updates/sync-to-desync-subsurf-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3a56f260a12df2c07b0d95f2bedd518f2d4cb061 GIT binary patch literal 18621 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ξ5oqLG$`A_9_05Zk(PP|Jd=jbcma%tD;e3l+TWJ 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 P0|SGntDnm{r-UW|Uh!wq literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf-2.png b/doc/publican/html/images/content-updates/sync-to-desync-subsurf-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb6210c6594e2979d7177df8865866b098eddfe GIT binary patch literal 18069 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 b{rCNsD%r!pz`)??>gTe~DWM4fMP1|1 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf-3.png b/doc/publican/html/images/content-updates/sync-to-desync-subsurf-3.png new file mode 100644 index 0000000000000000000000000000000000000000..34bf7475ecf227af341f314e02e4a670861ce849 GIT binary patch literal 19371 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 literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio b/doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio new file mode 100644 index 00000000..7a72e0f6 --- /dev/null +++ b/doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/content-updates/sync-to-desync-transition-1.png b/doc/publican/html/images/content-updates/sync-to-desync-transition-1.png new file mode 100644 index 0000000000000000000000000000000000000000..cd69f3c34da5cf101bd2d0703225b7e695e1c03b GIT binary patch literal 9299 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 E0Lwg-GXMYp literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-transition-2.png b/doc/publican/html/images/content-updates/sync-to-desync-transition-2.png new file mode 100644 index 0000000000000000000000000000000000000000..677a0cdb1b182a19442633be3597337c6c869de9 GIT binary patch literal 15177 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 A_5c6? literal 0 HcmV?d00001 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-transition.drawio b/doc/publican/html/images/content-updates/sync-to-desync-transition.drawio new file mode 100644 index 00000000..9843acb6 --- /dev/null +++ b/doc/publican/html/images/content-updates/sync-to-desync-transition.drawio @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/meson.build b/doc/publican/html/images/meson.build index de4cc181..c06e9be8 100644 --- a/doc/publican/html/images/meson.build +++ b/doc/publican/html/images/meson.build @@ -10,6 +10,8 @@ foreach src : files([ ) endforeach +subdir('content-updates') + foreach src : files([ 'wayland-architecture.gv', 'x-architecture.gv', diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 2edf7988..fb730f5f 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -15,6 +15,7 @@ foreach src : files([ 'Protocol.xml', 'Xwayland.xml', 'Compositors.xml', + 'Content_Updates.xml', 'Color.xml', 'Client.xml', 'Server.xml', From 11be42e8eac3d07883f829d3ac94d0b06b3e2b12 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 30 Dec 2025 10:34:46 +0200 Subject: [PATCH 1110/1152] editorconfig: follow wayland-protocols XML style It's unlikely that protocols/wayland.xml sees much change anymore, but files in doc/ might. To make writing documentation easier, stick to an unsurprising indentation style that is already in use in wayland-protocols and for the XSL files. Signed-off-by: Pekka Paalanen --- .editorconfig | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.editorconfig b/.editorconfig index cd9aa7f6..2bd707e8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,12 +9,7 @@ indent_style = tab indent_size = 8 max_line_length = 80 -[*.xml] -indent_style = tab -indent_size = 2 -tab_width = 8 - -[*.xsl] +[*.{xml,xsl}] indent_style = space indent_size = 2 tab_width = 8 From f7f08140c0d4dc2eadc32d1028168a21c1d5aa1f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 30 Dec 2025 11:41:29 +0200 Subject: [PATCH 1111/1152] doc: fix a root element validation error Once I got XML validation working in VSCode, it found an error: Document root element "preface", must match DOCTYPE root "chapter". I guess DOCTYPE declares which element is used as root in the file. Signed-off-by: Pekka Paalanen --- doc/publican/Foreword.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/publican/Foreword.xml b/doc/publican/Foreword.xml index 46fda2be..97908356 100644 --- a/doc/publican/Foreword.xml +++ b/doc/publican/Foreword.xml @@ -1,5 +1,5 @@ - %BOOK_ENTITIES; From 95c6014a7f93538f064cafe68d31a5e188809f03 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 30 Dec 2025 14:59:27 +0200 Subject: [PATCH 1112/1152] doc: document the Wayland XML dialect Document the XML tags used to describe Wayland protocols. Previously we only had the informal specification in the Protocol chapter, and the DTD. Better late than never. I have looked into wayland-scanner and libwayland for various limitations documented here possibly for the first time. I have also forbid things that are not in use or are known broken, including unspecified interface for a new_id in an event, or an object argument with an unspecified interface. I did investigate writing a RELAX NG compact schema for Wayland and documenting everything there, then generating DocBook XML from it. However, it seems generating documentation from schema is actually really complicated. I found these tools: - xs3p stylesheet: website looks dead, though Sourceforge still has it. Produces XHTML, not DocBook. Has an unfamiliar license. - xsddoc: the authors wrote that XSLT is not really sufficient, so they abandoned this approach and went for Java to create xnsdoc. - xnsdoc: seems to be proprietary licensed, although one could ask for a free license for a FLOSS project. All in all, it seems to be much easier to just write the documentation in DocBook, copying the strcture from the DTD manually, than to generate it. It's not doing to change often, anyway. It also allowed me to leverage DocBook syntax in full. Signed-off-by: Pekka Paalanen Signed-off-by: Pekka Paalanen --- doc/publican/Message_XML.xml | 928 +++++++++++++++++++++++++++++++++++ doc/publican/Wayland.xml | 1 + doc/publican/meson.build | 1 + 3 files changed, 930 insertions(+) create mode 100644 doc/publican/Message_XML.xml diff --git a/doc/publican/Message_XML.xml b/doc/publican/Message_XML.xml new file mode 100644 index 00000000..0188eead --- /dev/null +++ b/doc/publican/Message_XML.xml @@ -0,0 +1,928 @@ + + +%BOOK_ENTITIES; + +protocol"> +copyright"> +description"> +interface"> +enum"> +entry"> +request"> +event"> +arg"> + + + +]> + + + Message Definition Language + +

+ Overview + + + The fundamentals of the Wayland protocol are explained in + . This chapter formally defines the + language used to define Wayland protocols. + + + Wayland is an object-oriented protocol. Each object follows exactly + one interface. An interface is a collection of message and enumeration + definitions. A message can be either a request (sent by a client) + or an event (sent by a server). A message can have arguments. + All arguments are typed. + +
+ +
+ XML Elements + +
+ protocol + + protocol ::= (©right;?, &description;? &interface;+) + + + protocol is the root element in a Wayland protocol XML file. + Code generation tools may optionally use the protocol + name in API symbol names. The XML file name should be + similar to the protocol name. + + + The &description; element should be used to document the intended + purpose of the protocol, give an overview, and give any development + stage notices if applicable. + + + The ©right; element should be used to indicate the copyrights and + the license of the XML file. + + + + Required attributes + + + + name="cname" + + + + The name of the protocol (a.k.a protocol extension). + &cname-requirements; + + + The name should be globally unique. Protocols to be included in + wayland-protocols + must follow the naming rules set there. Other protocols should use + a unique prefix for the name, e.g. referring to the owning project's + name. + + + + +
+ + + +
+ description + + + Parent elements: &protocol;, &interface;, &request;, &event;, + &arg;, &enum;, &entry; + + + description ::= #PCDATA + + + Contains human-readable documentation for its parent element. + May contain formatted text, including paragraphs and bulleted + lists. + + + + Optional attributes + + + + summary="summary" + + + + A short (half a line at most) description of the documented + element. + + + When a &description; element is used, it is recommended to + not use the summary attribute of the parent + element. + + + + +
+ +
+ interface + + + Parent elements: &protocol; + + + interface ::= (&description;?, (&request;|&event;|&enum;)+) + + + An interface element contains the &request;s and &event;s that form the + interface. Enumerations can also be defined with &enum; elements. + These all belong into the namespace of the interface. Code generation + tools may use the interface name in API symbol names. + + + Interfaces form an ancestry tree. Aside from + , new protocol objects are + always created through an existing protocol object that may be referred to + as the factory object. + This can happen in one of two ways: the factory object's interface either + defines or does not define the new object's interface. + + + When the factory interface defines the new object's interface, the new + object also inherits the factory object's interface version number. + This number defines the interface version of the new object. + The factory object is referred to as + the parent object and the factory interface is + referred to as the parent interface. This + forms the ancestry tree of interfaces. + + + When the factory interface does not define the new object's interface, + both the interface name and the version must be communicated explicitly. + The foremost example of this is + . + In this case the terms "parent" or "ancestor" are not used. Interfaces + that are advertised through + are called global interfaces, or globals for short. + + + If objects having the interface can cause protocol errors, the protocol + error codes must be defined within the interface with an &enum; + element with its name set to "error". + Protocol error codes are always specific to the interface of the object + referred to in . + + + The &description; element should be used to describe the purpose and + the general usage of the interface. + + + + Required attributes + + + + name="cname" + + + + The name of the interface. &cname-requirements; + The name must be unique in the &protocol;, and preferably it should + also be globally unique to avoid API conflicts in language bindings + of multiple protocols. + + + Protocols to be included in + wayland-protocols + must follow the interface naming rules set there. Other protocols + should use a unique prefix for the name, e.g. referring to the owning + project's name. + + + + + + version="V" + + + + The interface's latest version number V must + be an integer greater than zero. An interface element defines + all versions of the interface from 1 to V + inclusive. The contents of each interface version are defined in each of + the &request;, &event;, &enum; and &entry; elements using the attributes + since and deprecated-since, and + in the specification text. + + + When an interface is extended, the version number must be incremented + on all the interfaces part of the same interface ancestry tree. + The exception to this rule are interfaces which are forever stuck + to version 1, which is usually caused by having multiple parent + interfaces with independent ancestor global interfaces. + + + A protocol object may have any defined version of the interface. + The version of the object is determined at runtime either + by inheritance from another protocol object or explicitly. + + + It is possible for a protocol object to have a version higher than + defined by its interface. This may happen when the interface is + stuck at version 1 as per above. It may also happen when a protocol + XML file has not been thoroughly updated as required. In such cases + the object shall function as with the highest defined interface + version. + + + + +
+ +
+ request + + + Parent elements: &interface; + + + request ::= (&description;?, &arg;*) + + + Defines a request, a message from a client to a server. + Requests are always associated with a specific protocol object. + + + Requests are automatically assigned opcodes in the order they + appear inside the &interface; element. Therefore the only + backwards-compatible way to add requests to an interface is to + add them to the end. Any &event; elements do not interfere + with request opcode assignments. + + + The &arg; elements declare the request's arguments. + There can be 0 to 20 arguments for a request. + The order of &arg; inside the request element defines the order of + the arguments on the wire. All declared arguments are mandatory, + and extra arguments are not allowed on the wire. + + + The &description; element should be used to document the request. + + + + Required attributes + + + + name="cname" + + + + The name of the request. &cname-requirements; + The name must be unique within all requests and &event;s in the + containing &interface;. + + + Code and language binding generators may use the name in the API + they create. The name of the containing + &interface; provides the namespace for requests. + + + + + + + Optional attributes + + + + type="destructor" + + + + When this attribute is present, the request is a destructor: + it shall destroy the protocol object it is sent on. Protocol IPC + libraries may use this for bookkeeping protocol object lifetimes. + + + Libwayland-client uses this information to ignore incoming &event;s + for destroyed protocol objects. Such events may occur due to a + natural race condition between the client destroying a protocol + object and the server sending events before processing the + destroy request. + + + + + + since="S" + + + + S must be an integer greater than zero. + If since is not specified, + since="1" is assumed. + + + This request was added in &interface; version + S. The request does not exist if the + protocol object has a bound version smaller than + S. Attempts to use it in such a case + shall raise the protocol error + wl_display.error.invalid_method. + + + + + + deprecated-since="D" + + + + D must be an integer greater than the + value of since. + If deprecated-since is not specified, then + the request is not deprecated in any version of the containing + &interface;. + + + This request was deprecated in &interface; version + D and above, and should not be sent on + protocol objects of such version. This is informational. + Compositors must still be prepared to handle the + request unless specified otherwise. + + + + +
+ +
+ event + + + Parent elements: &interface; + + + event ::= (&description;?, &arg;*) + + + Defines an event, a message from a server to a client. + Events are always associated with a specific protocol object. + + + Events are automatically assigned opcodes in the order they + appear inside the &interface; element. Therefore the only + backwards-compatible way to add events to an interface is to + add them to the end. Any &request; elements do not interfere + with event opcode assignments. + + + The &arg; elements declare the event's arguments. + There can be 0 to 20 arguments for an event. + The order of &arg; inside the event element defines the order of + the arguments on the wire. All declared arguments are mandatory, + and extra arguments are not allowed on the wire. + + + The &description; element should be used to document the event. + + + + Required attributes + + + + name="cname" + + + + The name of the event. &cname-requirements; + The name must be unique within all &request;s and events in the + containing &interface;. + + + Code and language binding generators may use the name in the API + they create. The name of the containing + &interface; provides the namespace for events. + + + + + + + Optional attributes + + + + type="destructor" + + + + When this attribute is present, the event is a destructor: + it shall destroy the protocol object it is sent on. Protocol IPC + libraries may use this for bookkeeping protocol object lifetimes. + + + + Destructor events are an underdeveloped feature in Wayland. + They can be used only on client-created protocol objects, and + it is the protocol designer's responsibility + to design such a message exchange that race conditions cannot + occur. The main problem would be a client sending a request at the + same time as the server is sending a destructor event. The + server will consider the protocol object to be already invalid + or even recycled when it proceeds to process the request. + This often results in protocol errors, but under specific + conditions it might also result in silently incorrect behavior. + + + Destructor events should not be used in new protocols. + If a destructor event is necessary, the simplest way to avoid + these problems is to have the &interface; not contain any + &request;s. + + + + + + + since="S" + + + + S must be an integer greater than zero. + If since is not specified, + since="1" is assumed. + + + This event was added in &interface; version + S. The event does not exist if the + protocol object has a bound version smaller than + S. + + + + + + deprecated-since="D" + + + + D must be an integer greater than the + value of since. + If deprecated-since is not specified, then + the event is not deprecated in any version of the containing + &interface;. + + + This event was deprecated in &interface; version + D and above, and should not be sent on + protocol objects of such version. This is informational. + Clients must still be prepared to receive this event + unless otherwise specified. + + + + +
+ +
+ arg + + + Parent elements: &request;, &event; + + + arg ::= &description;? + + + This element declares one argument for the request or the event. + + + + Required attributes + + + + name="cname" + + + + The name of the argument. &cname-requirements; + The name must be unique within all the arguments of the parent element. + + + + + + type="T" + + + + The type T of the argument datum must + be one of: + + + + int + + 32-bit signed integer. + + + + uint + + 32-bit unsigned integer. + + + + fixed + + Signed 24.8-bit fixed-point value. + + + + string + + + UTF-8 encoded string value, NUL byte terminated. + Interior NUL bytes are not allowed. + + + + + array + + A byte array of arbitrary data. + + + + fd + + A file descriptor. + + The file descriptor must be open and valid on send. + It is not possible to pass a null value. + + + + + new_id + + + Creates a new protocol object. A &request; or an &event; may + have at most one new_id argument. + + + If interface is specified, the new + protocol object shall have the specified &interface;, + and the new object's (interface) version shall be the + version of the object on which the &request; or &event; + is being sent. + + + If interface is not specified, the + &request; shall implicitly have two additional arguments: + A string for an &interface; name, and + a uint for the new object's version. + Leaving the interface unspecified is reserved for special use, + + for example. + + + + An &event; argument must always specify the + new_id interface. + + + + + + object + + Reference to an existing protocol object. + + The attribute interface should be + specified. Otherwise IPC libraries cannot enforce the + interface, and checking the interface falls on user code + and specification text. + + + + + + + + + + Optional attributes + + + + summary="summary" + + + + A short (half a line at most) description. This attribute + should not be used if a &description; is used. + + + + + + interface="iface" + + + + If given, iface must be the + name of some &interface;, and + type of this argument must be either + "object" or "new_id". + This indicates that the existing or new object must have + the interface iface. + Use for other argument types is forbidden. + + + + If an interface from another protocol is used, then this + creates a dependency between the protocols. If an application + generates code for one protocol, then it must also generate + code for all dependencies. Therefore this would not be a + backwards compatible change. + + + + + + + allow-null="true" | "false" + + + + Whether the argument value can be null on send. + Defaults to "false", meaning it is illegal + to send a null value. + Can be used only when type is + "string" or "object". + + + + Even though this attribute can be used to forbid a compositor + from sending a null object as an event argument, an IPC library + implementation may not protect the client from receiving a null + object. This can happen with libwayland-client when the client + has destroyed the protocol object before dispatching an event + that referred to it in an argument. + + + + + + + enum="enum-cname-suffix" + + + + If specified, indicates that the argument value should come from the + &enum; named enum-cname-suffix. If the + enumeration is a bitfield, then type must be + "uint". Otherwise type must + be either "uint" or "int". + + + The name enum-cname-suffix refers to an &enum; + in the same &interface; by default. If it is necessary to refer to an + enumeration from another interface, the interface name can be + given with a period: + enum="iface.enum-cname-suffix" + + + + This attribute alone does not automatically restrict the legal + values for this argument. + If values from outside of the enumeration need to be forbidden, + that must be specified explicitly in the documentation. + + + A common design pattern is to have the server advertise the + supported enumeration or bit values with &event;s and + explicitly forbid clients from using any other values in + requests. This also requires a protocol error code to be + specified with the error &enum; to be raised if a client + uses an illegal value, see + . + + + + + +
+ +
+ enum + + + Parent elements: &protocol; + + + enum ::= (&description;?, &entry;*) + + + This tag defines an enumeration of integer values. Enumerations are + merely a syntactic construct to give names to arbitrary integer + constants. Each constant is listed as an &entry; with its name. + There are two types of enumerations: regular enumerations and bitfields. + + + Regular enumerations do not use bitfield + attribute, or they set it to "false". + The set of pre-defined values that belong to a regular enumeration is + exactly the set of values listed as &entry; elements after + the protocol object version is taken into account. + See the &entry; attributes since and + deprecated-since. + + + Bitfields set bitfield to + "true". The set of values that belong to a + bitfield enumeration are all the values that can be formed by + the bitwise-or operator from the set of values listed as &entry; + elements like in the regular enumeration. Usually also zero is + implicitly included. + + + All the values in a regular enumeration must be either + signed or unsigned 32-bit integers. All the values in a + bitfield enumeration must be unsigned 32-bit integers. + + + + Required attributes + + + + name="cname-suffix" + + + + The name of the enumeration. &cname-suffix-requirements; + The name must be unique within all enumerations in the containing + &interface;. The name is used as the namespace for all the + contained &entry; elements. + + + + + + + Optional attributes + + + + since="S" + + + + S must be an integer greater than zero. + If since is not specified, + since="1" is assumed. + + + This enumeration was added in &interface; version + S. The enumeration does not exist if the + protocol object has a bound version smaller than + S. + + + + + + bitfield="true" | "false" + + + + Specifies if this enumeration is a bitfield. + Defaults to "false". + + + + +
+ +
+ entry + + + Parent elements: &enum; + + + entry ::= &description;? + + + Defines a name for an integer constant and makes it part of the + set of values of the containing enumeration. + + + + Required attributes + + + + name="cname-suffix" + + + + The name of a value in an enumeration. &cname-suffix-requirements; + The name must be unique within all entry elements in the containing + &enum;. + + + + + + value="V" + + + + An integer value. + The value can be given in decimal, hexadecimal, or octal + representation. + + + + + + + Optional attributes + + + + summary="summary" + + + + A short (half a line at most) description. This attribute + should not be used if a &description; is used. + + + + + + since="S" + + + + S must be an integer greater than zero. + If since is not specified, + since="1" is assumed. + + + This value was added in &interface; version + S. + + + + + + deprecated-since="D" + + + + D must be an integer greater than the + value of since. + If deprecated-since is not specified, then + the value is not deprecated in any version of the containing + &interface;. + + + This value was removed in &interface; version + D. This does not make the value + automatically illegal to use, see + attribute + enum. + + + + +
+
+ diff --git a/doc/publican/Wayland.xml b/doc/publican/Wayland.xml index f02a97fc..049a35f9 100644 --- a/doc/publican/Wayland.xml +++ b/doc/publican/Wayland.xml @@ -10,6 +10,7 @@ + diff --git a/doc/publican/meson.build b/doc/publican/meson.build index fb730f5f..2cb95b96 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -19,6 +19,7 @@ foreach src : files([ 'Color.xml', 'Client.xml', 'Server.xml', + 'Message_XML.xml', ]) name = fs.name(src) publican_inputs += fs.copyfile(name) From 8b102c3bc45681c5753a62f97118c928d2008d64 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 31 Dec 2025 14:05:36 +0200 Subject: [PATCH 1113/1152] doc/css: adjust code and userinput styles I don't know why was defined to be bold, it looks bad to me. The same with which would inherit bold from
when used inside a variablelist term. So, to make the code snippets look better, force them to use normal weight. should differentiate from normal code somehow, and italic seems fine for it. already has bold, and I think it's fine, so no need to touch it. These changes are mainly for the new XML dialect documentation chapter. I didn't notice anything changing for the older or generated parts of the docs. Signed-off-by: Pekka Paalanen --- doc/publican/html/css/common.css | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/publican/html/css/common.css b/doc/publican/html/css/common.css index d9c53e8f..40b5c4ec 100644 --- a/doc/publican/html/css/common.css +++ b/doc/publican/html/css/common.css @@ -860,7 +860,7 @@ code { font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; white-space: pre-wrap; word-wrap: break-word; - font-weight:bold; + font-weight: normal; } .parameter code { @@ -878,6 +878,14 @@ code.email { } +.synopsis { + font-weight: normal; +} + +.userinput { + font-style: italic; +} + /*Notifications*/ div.warning, div.note, div.important { color: black; From bb7b284623a474c0a8ce3d96c77d8aa0bd8dff50 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 2 Sep 2025 14:09:55 +0200 Subject: [PATCH 1114/1152] doc: update GPU buffer exchange section Finally, a buffer exchange mechanism for the 21st century. Signed-off-by: Julian Orth --- doc/publican/Architecture.xml | 148 ++++++++++++++++++++++------------ doc/publican/meson.build | 1 + 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/doc/publican/Architecture.xml b/doc/publican/Architecture.xml index b8a104cf..fb317685 100644 --- a/doc/publican/Architecture.xml +++ b/doc/publican/Architecture.xml @@ -280,65 +280,113 @@
- Hardware Enabling for Wayland + Accelerated GPU Buffer Exchange - Typically, hardware enabling includes modesetting/display - and EGL/GLES2. On top of that Wayland needs a way to share - buffers efficiently between processes. There are two sides - to that, the client side and the server side. + Clients + exchange + GPU buffers with the compositor as dma-buf file descriptors, which are universal handles + that are independent of any particular rendering API or memory allocator. The + linux-dmabuf-v1 + protocol is used to turn one or more dma-buf FDs into a + wl_buffer. - On the client side we've defined a Wayland EGL platform. In - the EGL model, that consists of the native types - (EGLNativeDisplayType, EGLNativeWindowType and - EGLNativePixmapType) and a way to create those types. In - other words, it's the glue code that binds the EGL stack and - its buffer sharing mechanism to the generic Wayland API. The - EGL stack is expected to provide an implementation of the - Wayland EGL platform. The full API is in the wayland-egl.h - header. The open source implementation in the mesa EGL stack - is in wayland-egl.c and platform_wayland.c. + If the client uses the + Vulkan + or + EGL + (via + wayland-egl) + window-system integration + (WSI), this is done transparently by the WSI. - Under the hood, the EGL stack is expected to define a - vendor-specific protocol extension that lets the client side - EGL stack communicate buffer details with the compositor in - order to share buffers. The point of the wayland-egl.h API - is to abstract that away and just let the client create an - EGLSurface for a Wayland surface and start rendering. The - open source stack uses the drm Wayland extension, which lets - the client discover the drm device to use and authenticate - and then share drm (GEM) buffers with the compositor. + Clients can alternatively allocate and import dma-bufs themselves + using the GBM library, Vulkan, udmabuf, or dma-buf heaps. + + + + + Using GBM, the client can allocate a gbm_bo and export one or more + dma-buf FDs from it. + + + + + Using Vulkan, the client can create a VkDeviceMemory object and use + VK_EXT_external_memory_dma_buf + and + VK_EXT_image_drm_format_modifier + to export a dma-buf FD from it. + + + + + udmabuf + can be used to create dma-buf FDs from linear host memory. + + + + + Dma-buf heaps + can be used by privileged applications to create dma-buf FDs on embedded + devices. + + + + + Compositors use + VK_EXT_external_memory_dma_buf + and + VK_EXT_image_drm_format_modifier + or + EGL_EXT_image_dma_buf_import + and + EGL_EXT_image_dma_buf_import_modifiers + to import the dma-bufs provided by the client into their own Vulkan or + EGL renderers. - The server side of Wayland is the compositor and core UX for - the vertical, typically integrating task switcher, app - launcher, lock screen in one monolithic application. The - server runs on top of a modesetting API (kernel modesetting, - OpenWF Display or similar) and composites the final UI using - a mix of EGL/GLES2 compositor and hardware overlays if - available. Enabling modesetting, EGL/GLES2 and overlays is - something that should be part of standard hardware bringup. - The extra requirement for Wayland enabling is the - EGL_WL_bind_wayland_display extension that lets the - compositor create an EGLImage from a generic Wayland shared - buffer. It's similar to the EGL_KHR_image_pixmap extension - to create an EGLImage from an X pixmap. + Clients do not need to wait for the GPU to finish rendering before submitting + dma-bufs to the compositor. Clients can use the + linux-drm-syncobj-v1 + protocol to exchange DRM synchronization objects with the compositor. These objects + are used to asynchronously signal ownership transfer of buffers from clients to the + compositor and vice versa. The WSIs do this transparently. - The extension has a setup step where you have to bind the - EGL display to a Wayland display. Then as the compositor - receives generic Wayland buffers from the clients (typically - when the client calls eglSwapBuffers), it will be able to - pass the struct wl_buffer pointer to eglCreateImageKHR as - the EGLClientBuffer argument and with EGL_WAYLAND_BUFFER_WL - as the target. This will create an EGLImage, which can then - be used by the compositor as a texture or passed to the - modesetting code to use as an overlay plane. Again, this is - implemented by the vendor specific protocol extension, which - on the server side will receive the driver specific details - about the shared buffer and turn that into an EGL image when - the user calls eglCreateImageKHR. + If the linux-drm-syncobj-v1 protocol is not supported by the compositor, clients + and compositors can use the + DMA_BUF_IOCTL_EXPORT_SYNC_FILE + and + DMA_BUF_IOCTL_IMPORT_SYNC_FILE + ioctls to access and create implicit synchronization barriers. + +
+
+ Display Programming + + Compositors enumerate DRM KMS devices using + udev. + Udev also notifies compositors of KMS device and display hotplug events. + + + Access to DRM KMS device ioctls is privileged. Since compositors usually run as + unprivileged applications, they typically gain access to a privileged file + descriptor using the + TakeDevice + method provided by logind. + + + Using the file descriptor, compositors use KMS + ioctls + to enumerate the available displays. + + + Compositors use + atomic mode setting + to change the buffer shown by the display, to change the display's resolution, to + enable or disable HDR, and so on.
diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 2cb95b96..1aa31d3c 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -98,6 +98,7 @@ custom_target( 'Wayland-docbook-html', command: [ xmlto, + '--skip-validation', '--stringparam', 'chunker.output.encoding=UTF-8', '--stringparam', 'chunk.section.depth=0', '--stringparam', 'toc.section.depth=1', From 77b9eb76369e27142b8be296b5f2eb1ca466272a Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 23 Jan 2026 15:05:14 +0100 Subject: [PATCH 1115/1152] protocol: reindent wayland.xml The file used a mixture of tabs and spaces. According to .editorconfig, all xml files should be indented with spaces, so this seems like the correct choice if we wanted to reindent the file. I used vim's :retab command to expand all tabs to 8 spaces. Signed-off-by: Julian Orth --- protocol/wayland.xml | 2774 +++++++++++++++++++++--------------------- 1 file changed, 1387 insertions(+), 1387 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index de6756b4..58e5649e 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -36,47 +36,47 @@ - The sync request asks the server to emit the 'done' event - on the returned wl_callback object. Since requests are - handled in-order and events are delivered in-order, this can - be used as a barrier to ensure all previous requests and the - resulting events have been handled. + The sync request asks the server to emit the 'done' event + on the returned wl_callback object. Since requests are + handled in-order and events are delivered in-order, this can + be used as a barrier to ensure all previous requests and the + resulting events have been handled. - The object returned by this request will be destroyed by the - compositor after the callback is fired and as such the client must not - attempt to use it after that point. + The object returned by this request will be destroyed by the + compositor after the callback is fired and as such the client must not + attempt to use it after that point. - The callback_data passed in the callback is undefined and should be ignored. + The callback_data passed in the callback is undefined and should be ignored. + summary="callback object for the sync request"/> - This request creates a registry object that allows the client - to list and bind the global objects available from the - compositor. + This request creates a registry object that allows the client + to list and bind the global objects available from the + compositor. - It should be noted that the server side resources consumed in - response to a get_registry request can only be released when the - client disconnects, not when the client side proxy is destroyed. - Therefore, clients should invoke get_registry as infrequently as - possible to avoid wasting memory. + It should be noted that the server side resources consumed in + response to a get_registry request can only be released when the + client disconnects, not when the client side proxy is destroyed. + Therefore, clients should invoke get_registry as infrequently as + possible to avoid wasting memory. + summary="global registry object"/> - The error event is sent out when a fatal (non-recoverable) - error has occurred. The object_id argument is the object - where the error occurred, most often in response to a request - to that object. The code identifies the error and is defined - by the object interface. As such, each interface defines its - own set of error codes. The message is a brief description - of the error, for (debugging) convenience. + The error event is sent out when a fatal (non-recoverable) + error has occurred. The object_id argument is the object + where the error occurred, most often in response to a request + to that object. The code identifies the error and is defined + by the object interface. As such, each interface defines its + own set of error codes. The message is a brief description + of the error, for (debugging) convenience. @@ -85,26 +85,26 @@ - These errors are global and can be emitted in response to any - server request. + These errors are global and can be emitted in response to any + server request. + summary="server couldn't find object"/> + summary="method doesn't exist on the specified interface or malformed request"/> + summary="server is out of memory"/> + summary="implementation error in compositor"/> - This event is used internally by the object ID management - logic. When a client deletes an object that it had created, - the server will send this event to acknowledge that it has - seen the delete request. When the client receives this event, - it will know that it can safely reuse the object ID. + This event is used internally by the object ID management + logic. When a client deletes an object that it had created, + the server will send this event to acknowledge that it has + seen the delete request. When the client receives this event, + it will know that it can safely reuse the object ID. @@ -136,8 +136,8 @@ - Binds a new, client-created object to the server using the - specified name as the identifier. + Binds a new, client-created object to the server using the + specified name as the identifier. @@ -145,11 +145,11 @@ - Notify the client of global objects. + Notify the client of global objects. - The event notifies the client that a global object with - the given name is now available, and it implements the - given version of the given interface. + The event notifies the client that a global object with + the given name is now available, and it implements the + given version of the given interface. @@ -158,16 +158,16 @@ - Notify the client of removed global objects. + Notify the client of removed global objects. - This event notifies the client that the global identified - by name is no longer available. If the client bound to - the global using the bind request, the client should now - destroy that object. + This event notifies the client that the global identified + by name is no longer available. If the client bound to + the global using the bind request, the client should now + destroy that object. - The object remains valid and requests to the object will be - ignored until the client destroys it, to avoid races between - the global going away and a client sending a request to it. + The object remains valid and requests to the object will be + ignored until the client destroys it, to avoid races between + the global going away and a client sending a request to it. @@ -184,7 +184,7 @@ - Notify the client when the related request is done. + Notify the client when the related request is done. @@ -199,14 +199,14 @@ - Ask the compositor to create a new surface. + Ask the compositor to create a new surface. - Ask the compositor to create a new region. + Ask the compositor to create a new region. @@ -225,17 +225,17 @@ - Create a wl_buffer object from the pool. + Create a wl_buffer object from the pool. - The buffer is created offset bytes into the pool and has - width and height as specified. The stride argument specifies - the number of bytes from the beginning of one row to the beginning - of the next. The format is the pixel format of the buffer and - must be one of those advertised through the wl_shm.format event. + The buffer is created offset bytes into the pool and has + width and height as specified. The stride argument specifies + the number of bytes from the beginning of one row to the beginning + of the next. The format is the pixel format of the buffer and + must be one of those advertised through the wl_shm.format event. - A buffer will keep a reference to the pool it was created from - so it is valid to destroy the pool immediately after creating - a buffer from it. + A buffer will keep a reference to the pool it was created from + so it is valid to destroy the pool immediately after creating + a buffer from it. @@ -247,26 +247,26 @@ - Destroy the shared memory pool. + Destroy the shared memory pool. - The mmapped memory will be released when all - buffers that have been created from this pool - are gone. + The mmapped memory will be released when all + buffers that have been created from this pool + are gone. - This request will cause the server to remap the backing memory - for the pool from the file descriptor passed when the pool was - created, but using the new size. This request can only be - used to make the pool bigger. + This request will cause the server to remap the backing memory + for the pool from the file descriptor passed when the pool was + created, but using the new size. This request can only be + used to make the pool bigger. - This request only changes the amount of bytes that are mmapped - by the server and does not touch the file corresponding to the - file descriptor passed at creation time. It is the client's - responsibility to ensure that the file is at least as big as - the new pool size. + This request only changes the amount of bytes that are mmapped + by the server and does not touch the file corresponding to the + file descriptor passed at creation time. It is the client's + responsibility to ensure that the file is at least as big as + the new pool size. @@ -287,7 +287,7 @@ - These errors can be emitted in response to wl_shm requests. + These errors can be emitted in response to wl_shm requests. @@ -296,21 +296,21 @@ - This describes the memory layout of an individual pixel. + This describes the memory layout of an individual pixel. - All renderers should support argb8888 and xrgb8888 but any other - formats are optional and may not be supported by the particular - renderer in use. + All renderers should support argb8888 and xrgb8888 but any other + formats are optional and may not be supported by the particular + renderer in use. - The drm format codes match the macros defined in drm_fourcc.h, except - argb8888 and xrgb8888. The formats actually supported by the compositor - will be reported by the format event. + The drm format codes match the macros defined in drm_fourcc.h, except + argb8888 and xrgb8888. The formats actually supported by the compositor + will be reported by the format event. - For all wl_shm formats and unless specified in another protocol - extension, pre-multiplied alpha is used for pixel values. + For all wl_shm formats and unless specified in another protocol + extension, pre-multiplied alpha is used for pixel values. + run the automated script that keeps it in sync with drm_fourcc.h. --> @@ -458,11 +458,11 @@ - Create a new wl_shm_pool object. + Create a new wl_shm_pool object. - The pool can be used to create shared memory based buffer - objects. The server will mmap size bytes of the passed file - descriptor, to use as backing memory for the pool. + The pool can be used to create shared memory based buffer + objects. The server will mmap size bytes of the passed file + descriptor, to use as backing memory for the pool. @@ -471,9 +471,9 @@ - Informs the client about a valid pixel format that - can be used for buffers. Known formats include - argb8888 and xrgb8888. + Informs the client about a valid pixel format that + can be used for buffers. Known formats include + argb8888 and xrgb8888. @@ -482,10 +482,10 @@ - Using this request a client can tell the server that it is not going to - use the shm object anymore. + Using this request a client can tell the server that it is not going to + use the shm object anymore. - Objects created via this interface remain unaffected. + Objects created via this interface remain unaffected. @@ -511,29 +511,29 @@ - Destroy a buffer. If and how you need to release the backing - storage is defined by the buffer factory interface. + Destroy a buffer. If and how you need to release the backing + storage is defined by the buffer factory interface. - For possible side-effects to a surface, see wl_surface.attach. + For possible side-effects to a surface, see wl_surface.attach. - Sent when this wl_buffer is no longer used by the compositor. + Sent when this wl_buffer is no longer used by the compositor. - For more information on when release events may or may not be sent, - and what consequences it has, please see the description of - wl_surface.attach. + For more information on when release events may or may not be sent, + and what consequences it has, please see the description of + wl_surface.attach. - If a client receives a release event before the frame callback - requested in the same wl_surface.commit that attaches this - wl_buffer to a surface, then the client is immediately free to - reuse the buffer and its backing storage, and does not need a - second buffer for the next surface content update. Typically - this is possible, when the compositor maintains a copy of the - wl_surface contents, e.g. as a GL texture. This is an important - optimization for GL(ES) compositors with wl_shm clients. + If a client receives a release event before the frame callback + requested in the same wl_surface.commit that attaches this + wl_buffer to a surface, then the client is immediately free to + reuse the buffer and its backing storage, and does not need a + second buffer for the next surface content update. Typically + this is possible, when the compositor maintains a copy of the + wl_surface contents, e.g. as a GL texture. This is an important + optimization for GL(ES) compositors with wl_shm clients. @@ -550,31 +550,31 @@ + summary="finish request was called untimely"/> + summary="action mask contains invalid values"/> + summary="action argument has an invalid value"/> + summary="offer doesn't accept this request"/> - Indicate that the client can accept the given mime type, or - NULL for not accepted. + Indicate that the client can accept the given mime type, or + NULL for not accepted. - For objects of version 2 or older, this request is used by the - client to give feedback whether the client can receive the given - mime type, or NULL if none is accepted; the feedback does not - determine whether the drag-and-drop operation succeeds or not. + For objects of version 2 or older, this request is used by the + client to give feedback whether the client can receive the given + mime type, or NULL if none is accepted; the feedback does not + determine whether the drag-and-drop operation succeeds or not. - For objects of version 3 or newer, this request determines the - final result of the drag-and-drop operation. If the end result - is that no mime types were accepted, the drag-and-drop operation - will be cancelled and the corresponding drag source will receive - wl_data_source.cancelled. Clients may still use this event in - conjunction with wl_data_source.action for feedback. + For objects of version 3 or newer, this request determines the + final result of the drag-and-drop operation. If the end result + is that no mime types were accepted, the drag-and-drop operation + will be cancelled and the corresponding drag source will receive + wl_data_source.cancelled. Clients may still use this event in + conjunction with wl_data_source.action for feedback. @@ -582,21 +582,21 @@ - To transfer the offered data, the client issues this request - and indicates the mime type it wants to receive. The transfer - happens through the passed file descriptor (typically created - with the pipe system call). The source client writes the data - in the mime type representation requested and then closes the - file descriptor. + To transfer the offered data, the client issues this request + and indicates the mime type it wants to receive. The transfer + happens through the passed file descriptor (typically created + with the pipe system call). The source client writes the data + in the mime type representation requested and then closes the + file descriptor. - The receiving client reads from the read end of the pipe until - EOF and then closes its end, at which point the transfer is - complete. + The receiving client reads from the read end of the pipe until + EOF and then closes its end, at which point the transfer is + complete. - This request may happen multiple times for different mime types, - both before and after wl_data_device.drop. Drag-and-drop destination - clients may preemptively fetch data or examine it more closely to - determine acceptance. + This request may happen multiple times for different mime types, + both before and after wl_data_device.drop. Drag-and-drop destination + clients may preemptively fetch data or examine it more closely to + determine acceptance. @@ -604,14 +604,14 @@ - Destroy the data offer. + Destroy the data offer. - Sent immediately after creating the wl_data_offer object. One - event per offered mime type. + Sent immediately after creating the wl_data_offer object. One + event per offered mime type. @@ -620,114 +620,114 @@ - Notifies the compositor that the drag destination successfully - finished the drag-and-drop operation. + Notifies the compositor that the drag destination successfully + finished the drag-and-drop operation. - Upon receiving this request, the compositor will emit - wl_data_source.dnd_finished on the drag source client. + Upon receiving this request, the compositor will emit + wl_data_source.dnd_finished on the drag source client. - It is a client error to perform other requests than - wl_data_offer.destroy after this one. It is also an error to perform - this request after a NULL mime type has been set in - wl_data_offer.accept or no action was received through - wl_data_offer.action. + It is a client error to perform other requests than + wl_data_offer.destroy after this one. It is also an error to perform + this request after a NULL mime type has been set in + wl_data_offer.accept or no action was received through + wl_data_offer.action. - If wl_data_offer.finish request is received for a non drag and drop - operation, the invalid_finish protocol error is raised. + If wl_data_offer.finish request is received for a non drag and drop + operation, the invalid_finish protocol error is raised. - Sets the actions that the destination side client supports for - this operation. This request may trigger the emission of - wl_data_source.action and wl_data_offer.action events if the compositor - needs to change the selected action. + Sets the actions that the destination side client supports for + this operation. This request may trigger the emission of + wl_data_source.action and wl_data_offer.action events if the compositor + needs to change the selected action. - This request can be called multiple times throughout the - drag-and-drop operation, typically in response to wl_data_device.enter - or wl_data_device.motion events. + This request can be called multiple times throughout the + drag-and-drop operation, typically in response to wl_data_device.enter + or wl_data_device.motion events. - This request determines the final result of the drag-and-drop - operation. If the end result is that no action is accepted, - the drag source will receive wl_data_source.cancelled. + This request determines the final result of the drag-and-drop + operation. If the end result is that no action is accepted, + the drag source will receive wl_data_source.cancelled. - The dnd_actions argument must contain only values expressed in the - wl_data_device_manager.dnd_actions enum, and the preferred_action - argument must only contain one of those values set, otherwise it - will result in a protocol error. + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, and the preferred_action + argument must only contain one of those values set, otherwise it + will result in a protocol error. - While managing an "ask" action, the destination drag-and-drop client - may perform further wl_data_offer.receive requests, and is expected - to perform one last wl_data_offer.set_actions request with a preferred - action other than "ask" (and optionally wl_data_offer.accept) before - requesting wl_data_offer.finish, in order to convey the action selected - by the user. If the preferred action is not in the - wl_data_offer.source_actions mask, an error will be raised. + While managing an "ask" action, the destination drag-and-drop client + may perform further wl_data_offer.receive requests, and is expected + to perform one last wl_data_offer.set_actions request with a preferred + action other than "ask" (and optionally wl_data_offer.accept) before + requesting wl_data_offer.finish, in order to convey the action selected + by the user. If the preferred action is not in the + wl_data_offer.source_actions mask, an error will be raised. - If the "ask" action is dismissed (e.g. user cancellation), the client - is expected to perform wl_data_offer.destroy right away. + If the "ask" action is dismissed (e.g. user cancellation), the client + is expected to perform wl_data_offer.destroy right away. - This request can only be made on drag-and-drop offers, a protocol error - will be raised otherwise. + This request can only be made on drag-and-drop offers, a protocol error + will be raised otherwise. + enum="wl_data_device_manager.dnd_action"/> + enum="wl_data_device_manager.dnd_action"/> - This event indicates the actions offered by the data source. It - will be sent immediately after creating the wl_data_offer object, - or anytime the source side changes its offered actions through - wl_data_source.set_actions. + This event indicates the actions offered by the data source. It + will be sent immediately after creating the wl_data_offer object, + or anytime the source side changes its offered actions through + wl_data_source.set_actions. + enum="wl_data_device_manager.dnd_action"/> - This event indicates the action selected by the compositor after - matching the source/destination side actions. Only one action (or - none) will be offered here. + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. - This event can be emitted multiple times during the drag-and-drop - operation in response to destination side action changes through - wl_data_offer.set_actions. + This event can be emitted multiple times during the drag-and-drop + operation in response to destination side action changes through + wl_data_offer.set_actions. - This event will no longer be emitted after wl_data_device.drop - happened on the drag-and-drop destination, the client must - honor the last action received, or the last preferred one set - through wl_data_offer.set_actions when handling an "ask" action. + This event will no longer be emitted after wl_data_device.drop + happened on the drag-and-drop destination, the client must + honor the last action received, or the last preferred one set + through wl_data_offer.set_actions when handling an "ask" action. - Compositors may also change the selected action on the fly, mainly - in response to keyboard modifier changes during the drag-and-drop - operation. + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. - The most recent action received is always the valid one. Prior to - receiving wl_data_device.drop, the chosen action may change (e.g. - due to keyboard modifiers being pressed). At the time of receiving - wl_data_device.drop the drag-and-drop destination must honor the - last action received. + The most recent action received is always the valid one. Prior to + receiving wl_data_device.drop, the chosen action may change (e.g. + due to keyboard modifiers being pressed). At the time of receiving + wl_data_device.drop the drag-and-drop destination must honor the + last action received. - Action changes may still happen after wl_data_device.drop, - especially on "ask" actions, where the drag-and-drop destination - may choose another action afterwards. Action changes happening - at this stage are always the result of inter-client negotiation, the - compositor shall no longer be able to induce a different action. + Action changes may still happen after wl_data_device.drop, + especially on "ask" actions, where the drag-and-drop destination + may choose another action afterwards. Action changes happening + at this stage are always the result of inter-client negotiation, the + compositor shall no longer be able to induce a different action. - Upon "ask" actions, it is expected that the drag-and-drop destination - may potentially choose a different action and/or mime type, - based on wl_data_offer.source_actions and finally chosen by the - user (e.g. popping up a menu with the available options). The - final wl_data_offer.set_actions and wl_data_offer.accept requests - must happen before the call to wl_data_offer.finish. + Upon "ask" actions, it is expected that the drag-and-drop destination + may potentially choose a different action and/or mime type, + based on wl_data_offer.source_actions and finally chosen by the + user (e.g. popping up a menu with the available options). The + final wl_data_offer.set_actions and wl_data_offer.accept requests + must happen before the call to wl_data_offer.finish. + enum="wl_data_device_manager.dnd_action"/> @@ -741,41 +741,41 @@ + summary="action mask contains invalid values"/> + summary="source doesn't accept this request"/> - This request adds a mime type to the set of mime types - advertised to targets. Can be called several times to offer - multiple types. + This request adds a mime type to the set of mime types + advertised to targets. Can be called several times to offer + multiple types. - Destroy the data source. + Destroy the data source. - Sent when a target accepts pointer_focus or motion events. If - a target does not accept any of the offered types, type is NULL. + Sent when a target accepts pointer_focus or motion events. If + a target does not accept any of the offered types, type is NULL. - Used for feedback during drag-and-drop. + Used for feedback during drag-and-drop. - Request for data from the client. Send the data as the - specified mime type over the passed file descriptor, then - close it. + Request for data from the client. Send the data as the + specified mime type over the passed file descriptor, then + close it. @@ -783,26 +783,26 @@ - This data source is no longer valid. There are several reasons why - this could happen: + This data source is no longer valid. There are several reasons why + this could happen: - - The data source has been replaced by another data source. - - The drag-and-drop operation was performed, but the drop destination - did not accept any of the mime types offered through - wl_data_source.target. - - The drag-and-drop operation was performed, but the drop destination - did not select any of the actions present in the mask offered through - wl_data_source.action. - - The drag-and-drop operation was performed but didn't happen over a - surface. - - The compositor cancelled the drag-and-drop operation (e.g. compositor - dependent timeouts to avoid stale drag-and-drop transfers). + - The data source has been replaced by another data source. + - The drag-and-drop operation was performed, but the drop destination + did not accept any of the mime types offered through + wl_data_source.target. + - The drag-and-drop operation was performed, but the drop destination + did not select any of the actions present in the mask offered through + wl_data_source.action. + - The drag-and-drop operation was performed but didn't happen over a + surface. + - The compositor cancelled the drag-and-drop operation (e.g. compositor + dependent timeouts to avoid stale drag-and-drop transfers). - The client should clean up and destroy this data source. + The client should clean up and destroy this data source. - For objects of version 2 or older, wl_data_source.cancelled will - only be emitted if the data source was replaced by another data - source. + For objects of version 2 or older, wl_data_source.cancelled will + only be emitted if the data source was replaced by another data + source. @@ -810,79 +810,79 @@ - Sets the actions that the source side client supports for this - operation. This request may trigger wl_data_source.action and - wl_data_offer.action events if the compositor needs to change the - selected action. + Sets the actions that the source side client supports for this + operation. This request may trigger wl_data_source.action and + wl_data_offer.action events if the compositor needs to change the + selected action. - The dnd_actions argument must contain only values expressed in the - wl_data_device_manager.dnd_actions enum, otherwise it will result - in a protocol error. + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, otherwise it will result + in a protocol error. - This request must be made once only, and can only be made on sources - used in drag-and-drop, so it must be performed before - wl_data_device.start_drag. Attempting to use the source other than - for drag-and-drop will raise a protocol error. + This request must be made once only, and can only be made on sources + used in drag-and-drop, so it must be performed before + wl_data_device.start_drag. Attempting to use the source other than + for drag-and-drop will raise a protocol error. + enum="wl_data_device_manager.dnd_action"/> - The user performed the drop action. This event does not indicate - acceptance, wl_data_source.cancelled may still be emitted afterwards - if the drop destination does not accept any mime type. + The user performed the drop action. This event does not indicate + acceptance, wl_data_source.cancelled may still be emitted afterwards + if the drop destination does not accept any mime type. - However, this event might however not be received if the compositor - cancelled the drag-and-drop operation before this event could happen. + However, this event might however not be received if the compositor + cancelled the drag-and-drop operation before this event could happen. - Note that the data_source may still be used in the future and should - not be destroyed here. + Note that the data_source may still be used in the future and should + not be destroyed here. - The drop destination finished interoperating with this data - source, so the client is now free to destroy this data source and - free all associated data. + The drop destination finished interoperating with this data + source, so the client is now free to destroy this data source and + free all associated data. - If the action used to perform the operation was "move", the - source can now delete the transferred data. + If the action used to perform the operation was "move", the + source can now delete the transferred data. - This event indicates the action selected by the compositor after - matching the source/destination side actions. Only one action (or - none) will be offered here. + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. - This event can be emitted multiple times during the drag-and-drop - operation, mainly in response to destination side changes through - wl_data_offer.set_actions, and as the data device enters/leaves - surfaces. + This event can be emitted multiple times during the drag-and-drop + operation, mainly in response to destination side changes through + wl_data_offer.set_actions, and as the data device enters/leaves + surfaces. - It is only possible to receive this event after - wl_data_source.dnd_drop_performed if the drag-and-drop operation - ended in an "ask" action, in which case the final wl_data_source.action - event will happen immediately before wl_data_source.dnd_finished. + It is only possible to receive this event after + wl_data_source.dnd_drop_performed if the drag-and-drop operation + ended in an "ask" action, in which case the final wl_data_source.action + event will happen immediately before wl_data_source.dnd_finished. - Compositors may also change the selected action on the fly, mainly - in response to keyboard modifier changes during the drag-and-drop - operation. + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. - The most recent action received is always the valid one. The chosen - action may change alongside negotiation (e.g. an "ask" action can turn - into a "move" operation), so the effects of the final action must - always be applied in wl_data_offer.dnd_finished. + The most recent action received is always the valid one. The chosen + action may change alongside negotiation (e.g. an "ask" action can turn + into a "move" operation), so the effects of the final action must + always be applied in wl_data_offer.dnd_finished. - Clients can trigger cursor surface changes from this point, so - they reflect the current action. + Clients can trigger cursor surface changes from this point, so + they reflect the current action. + enum="wl_data_device_manager.dnd_action"/> @@ -902,35 +902,35 @@ - This request asks the compositor to start a drag-and-drop - operation on behalf of the client. + This request asks the compositor to start a drag-and-drop + operation on behalf of the client. - The source argument is the data source that provides the data - for the eventual data transfer. If source is NULL, enter, leave - and motion events are sent only to the client that initiated the - drag and the client is expected to handle the data passing - internally. If source is destroyed, the drag-and-drop session will be - cancelled. + The source argument is the data source that provides the data + for the eventual data transfer. If source is NULL, enter, leave + and motion events are sent only to the client that initiated the + drag and the client is expected to handle the data passing + internally. If source is destroyed, the drag-and-drop session will be + cancelled. - The origin surface is the surface where the drag originates and - the client must have an active implicit grab that matches the - serial. + The origin surface is the surface where the drag originates and + the client must have an active implicit grab that matches the + serial. - The icon surface is an optional (can be NULL) surface that - provides an icon to be moved around with the cursor. Initially, - the top-left corner of the icon surface is placed at the cursor - hotspot, but subsequent wl_surface.offset requests can move the - relative position. Attach requests must be confirmed with - wl_surface.commit as usual. The icon surface is given the role of - a drag-and-drop icon. If the icon surface already has another role, - it raises a protocol error. + The icon surface is an optional (can be NULL) surface that + provides an icon to be moved around with the cursor. Initially, + the top-left corner of the icon surface is placed at the cursor + hotspot, but subsequent wl_surface.offset requests can move the + relative position. Attach requests must be confirmed with + wl_surface.commit as usual. The icon surface is given the role of + a drag-and-drop icon. If the icon surface already has another role, + it raises a protocol error. - The input region is ignored for wl_surfaces with the role of a - drag-and-drop icon. + The input region is ignored for wl_surfaces with the role of a + drag-and-drop icon. - The given source may not be used in any further set_selection or - start_drag requests. Attempting to reuse a previously-used source - may send a used_source error. + The given source may not be used in any further set_selection or + start_drag requests. Attempting to reuse a previously-used source + may send a used_source error. @@ -940,14 +940,14 @@ - This request asks the compositor to set the selection - to the data from the source on behalf of the client. + This request asks the compositor to set the selection + to the data from the source on behalf of the client. - To unset the selection, set the source to NULL. + To unset the selection, set the source to NULL. - The given source may not be used in any further set_selection or - start_drag requests. Attempting to reuse a previously-used source - may send a used_source error. + The given source may not be used in any further set_selection or + start_drag requests. Attempting to reuse a previously-used source + may send a used_source error. @@ -955,46 +955,46 @@ - The data_offer event introduces a new wl_data_offer object, - which will subsequently be used in either the - data_device.enter event (for drag-and-drop) or the - data_device.selection event (for selections). Immediately - following the data_device.data_offer event, the new data_offer - object will send out data_offer.offer events to describe the - mime types it offers. + The data_offer event introduces a new wl_data_offer object, + which will subsequently be used in either the + data_device.enter event (for drag-and-drop) or the + data_device.selection event (for selections). Immediately + following the data_device.data_offer event, the new data_offer + object will send out data_offer.offer events to describe the + mime types it offers. - This event is sent when an active drag-and-drop pointer enters - a surface owned by the client. The position of the pointer at - enter time is provided by the x and y arguments, in surface-local - coordinates. + This event is sent when an active drag-and-drop pointer enters + a surface owned by the client. The position of the pointer at + enter time is provided by the x and y arguments, in surface-local + coordinates. + summary="source data_offer object"/> - This event is sent when the drag-and-drop pointer leaves the - surface and the session ends. The client must destroy the - wl_data_offer introduced at enter time at this point. + This event is sent when the drag-and-drop pointer leaves the + surface and the session ends. The client must destroy the + wl_data_offer introduced at enter time at this point. - This event is sent when the drag-and-drop pointer moves within - the currently focused surface. The new position of the pointer - is provided by the x and y arguments, in surface-local - coordinates. + This event is sent when the drag-and-drop pointer moves within + the currently focused surface. The new position of the pointer + is provided by the x and y arguments, in surface-local + coordinates. @@ -1003,46 +1003,46 @@ - The event is sent when a drag-and-drop operation is ended - because the implicit grab is removed. + The event is sent when a drag-and-drop operation is ended + because the implicit grab is removed. - The drag-and-drop destination is expected to honor the last action - received through wl_data_offer.action, if the resulting action is - "copy" or "move", the destination can still perform - wl_data_offer.receive requests, and is expected to end all - transfers with a wl_data_offer.finish request. + The drag-and-drop destination is expected to honor the last action + received through wl_data_offer.action, if the resulting action is + "copy" or "move", the destination can still perform + wl_data_offer.receive requests, and is expected to end all + transfers with a wl_data_offer.finish request. - If the resulting action is "ask", the action will not be considered - final. The drag-and-drop destination is expected to perform one last - wl_data_offer.set_actions request, or wl_data_offer.destroy in order - to cancel the operation. + If the resulting action is "ask", the action will not be considered + final. The drag-and-drop destination is expected to perform one last + wl_data_offer.set_actions request, or wl_data_offer.destroy in order + to cancel the operation. - The selection event is sent out to notify the client of a new - wl_data_offer for the selection for this device. The - data_device.data_offer and the data_offer.offer events are - sent out immediately before this event to introduce the data - offer object. The selection event is sent to a client - immediately before receiving keyboard focus and when a new - selection is set while the client has keyboard focus. The - data_offer is valid until a new data_offer or NULL is received - or until the client loses keyboard focus. Switching surface with - keyboard focus within the same client doesn't mean a new selection - will be sent. The client must destroy the previous selection - data_offer, if any, upon receiving this event. + The selection event is sent out to notify the client of a new + wl_data_offer for the selection for this device. The + data_device.data_offer and the data_offer.offer events are + sent out immediately before this event to introduce the data + offer object. The selection event is sent to a client + immediately before receiving keyboard focus and when a new + selection is set while the client has keyboard focus. The + data_offer is valid until a new data_offer or NULL is received + or until the client loses keyboard focus. Switching surface with + keyboard focus within the same client doesn't mean a new selection + will be sent. The client must destroy the previous selection + data_offer, if any, upon receiving this event. + summary="selection data_offer object"/> - This request destroys the data device. + This request destroys the data device. @@ -1063,14 +1063,14 @@ - Create a new data source. + Create a new data source. - Create a new data device for a given seat. + Create a new data device for a given seat. @@ -1080,29 +1080,29 @@ - This is a bitmask of the available/preferred actions in a - drag-and-drop operation. + This is a bitmask of the available/preferred actions in a + drag-and-drop operation. - In the compositor, the selected action is a result of matching the - actions offered by the source and destination sides. "action" events - with a "none" action will be sent to both source and destination if - there is no match. All further checks will effectively happen on - (source actions ∩ destination actions). + In the compositor, the selected action is a result of matching the + actions offered by the source and destination sides. "action" events + with a "none" action will be sent to both source and destination if + there is no match. All further checks will effectively happen on + (source actions ∩ destination actions). - In addition, compositors may also pick different actions in - reaction to key modifiers being pressed. One common design that - is used in major toolkits (and the behavior recommended for - compositors) is: + In addition, compositors may also pick different actions in + reaction to key modifiers being pressed. One common design that + is used in major toolkits (and the behavior recommended for + compositors) is: - - If no modifiers are pressed, the first match (in bit order) - will be used. - - Pressing Shift selects "move", if enabled in the mask. - - Pressing Control selects "copy", if enabled in the mask. + - If no modifiers are pressed, the first match (in bit order) + will be used. + - Pressing Shift selects "move", if enabled in the mask. + - Pressing Control selects "copy", if enabled in the mask. - Behavior beyond that is considered implementation-dependent. - Compositors may for example bind other modifiers (like Alt/Meta) - or drags initiated with other buttons than BTN_LEFT to specific - actions (e.g. "ask"). + Behavior beyond that is considered implementation-dependent. + Compositors may for example bind other modifiers (like Alt/Meta) + or drags initiated with other buttons than BTN_LEFT to specific + actions (e.g. "ask"). @@ -1130,11 +1130,11 @@ - Create a shell surface for an existing surface. This gives - the wl_surface the role of a shell surface. If the wl_surface - already has another role, it raises a protocol error. + Create a shell surface for an existing surface. This gives + the wl_surface the role of a shell surface. If the wl_surface + already has another role, it raises a protocol error. - Only one shell surface can be associated with a given surface. + Only one shell surface can be associated with a given surface. @@ -1158,19 +1158,19 @@ - A client must respond to a ping event with a pong request or - the client may be deemed unresponsive. + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. - Start a pointer-driven move of the surface. + Start a pointer-driven move of the surface. - This request must be used in response to a button press event. - The server may ignore move requests depending on the state of - the surface (e.g. fullscreen or maximized). + This request must be used in response to a button press event. + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized). @@ -1178,10 +1178,10 @@ - These values are used to indicate which edge of a surface - is being dragged in a resize operation. The server may - use this information to adapt its behavior, e.g. choose - an appropriate cursor image. + These values are used to indicate which edge of a surface + is being dragged in a resize operation. The server may + use this information to adapt its behavior, e.g. choose + an appropriate cursor image. @@ -1196,11 +1196,11 @@ - Start a pointer-driven resizing of the surface. + Start a pointer-driven resizing of the surface. - This request must be used in response to a button press event. - The server may ignore resize requests depending on the state of - the surface (e.g. fullscreen or maximized). + This request must be used in response to a button press event. + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). @@ -1209,29 +1209,29 @@ - Map the surface as a toplevel surface. + Map the surface as a toplevel surface. - A toplevel surface is not fullscreen, maximized or transient. + A toplevel surface is not fullscreen, maximized or transient. - These flags specify details of the expected behaviour - of transient surfaces. Used in the set_transient request. + These flags specify details of the expected behaviour + of transient surfaces. Used in the set_transient request. - Map the surface relative to an existing surface. + Map the surface relative to an existing surface. - The x and y arguments specify the location of the upper left - corner of the surface relative to the upper left corner of the - parent surface, in surface-local coordinates. + The x and y arguments specify the location of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface-local coordinates. - The flags argument controls details of the transient behaviour. + The flags argument controls details of the transient behaviour. @@ -1241,9 +1241,9 @@ - Hints to indicate to the compositor how to deal with a conflict - between the dimensions of the surface and the dimensions of the - output. The compositor is free to ignore this parameter. + Hints to indicate to the compositor how to deal with a conflict + between the dimensions of the surface and the dimensions of the + output. The compositor is free to ignore this parameter. @@ -1253,67 +1253,67 @@ - Map the surface as a fullscreen surface. + Map the surface as a fullscreen surface. - If an output parameter is given then the surface will be made - fullscreen on that output. If the client does not specify the - output then the compositor will apply its policy - usually - choosing the output on which the surface has the biggest surface - area. + If an output parameter is given then the surface will be made + fullscreen on that output. If the client does not specify the + output then the compositor will apply its policy - usually + choosing the output on which the surface has the biggest surface + area. - The client may specify a method to resolve a size conflict - between the output size and the surface size - this is provided - through the method parameter. + The client may specify a method to resolve a size conflict + between the output size and the surface size - this is provided + through the method parameter. - The framerate parameter is used only when the method is set - to "driver", to indicate the preferred framerate. A value of 0 - indicates that the client does not care about framerate. The - framerate is specified in mHz, that is framerate of 60000 is 60Hz. + The framerate parameter is used only when the method is set + to "driver", to indicate the preferred framerate. A value of 0 + indicates that the client does not care about framerate. The + framerate is specified in mHz, that is framerate of 60000 is 60Hz. - A method of "scale" or "driver" implies a scaling operation of - the surface, either via a direct scaling operation or a change of - the output mode. This will override any kind of output scaling, so - that mapping a surface with a buffer size equal to the mode can - fill the screen independent of buffer_scale. + A method of "scale" or "driver" implies a scaling operation of + the surface, either via a direct scaling operation or a change of + the output mode. This will override any kind of output scaling, so + that mapping a surface with a buffer size equal to the mode can + fill the screen independent of buffer_scale. - A method of "fill" means we don't scale up the buffer, however - any output scale is applied. This means that you may run into - an edge case where the application maps a buffer with the same - size of the output mode but buffer_scale 1 (thus making a - surface larger than the output). In this case it is allowed to - downscale the results to fit the screen. + A method of "fill" means we don't scale up the buffer, however + any output scale is applied. This means that you may run into + an edge case where the application maps a buffer with the same + size of the output mode but buffer_scale 1 (thus making a + surface larger than the output). In this case it is allowed to + downscale the results to fit the screen. - The compositor must reply to this request with a configure event - with the dimensions for the output on which the surface will - be made fullscreen. + The compositor must reply to this request with a configure event + with the dimensions for the output on which the surface will + be made fullscreen. + summary="output on which the surface is to be fullscreen"/> - Map the surface as a popup. + Map the surface as a popup. - A popup surface is a transient surface with an added pointer - grab. + A popup surface is a transient surface with an added pointer + grab. - An existing implicit grab will be changed to owner-events mode, - and the popup grab will continue after the implicit grab ends - (i.e. releasing the mouse button does not cause the popup to - be unmapped). + An existing implicit grab will be changed to owner-events mode, + and the popup grab will continue after the implicit grab ends + (i.e. releasing the mouse button does not cause the popup to + be unmapped). - The popup grab continues until the window is destroyed or a - mouse button is pressed in any other client's window. A click - in any of the client's surfaces is reported as normal, however, - clicks in other clients' surfaces will be discarded and trigger - the callback. + The popup grab continues until the window is destroyed or a + mouse button is pressed in any other client's window. A click + in any of the client's surfaces is reported as normal, however, + clicks in other clients' surfaces will be discarded and trigger + the callback. - The x and y arguments specify the location of the upper left - corner of the surface relative to the upper left corner of the - parent surface, in surface-local coordinates. + The x and y arguments specify the location of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface-local coordinates. @@ -1325,81 +1325,81 @@ - Map the surface as a maximized surface. + Map the surface as a maximized surface. - If an output parameter is given then the surface will be - maximized on that output. If the client does not specify the - output then the compositor will apply its policy - usually - choosing the output on which the surface has the biggest surface - area. + If an output parameter is given then the surface will be + maximized on that output. If the client does not specify the + output then the compositor will apply its policy - usually + choosing the output on which the surface has the biggest surface + area. - The compositor will reply with a configure event telling - the expected new surface size. The operation is completed - on the next buffer attach to this surface. + The compositor will reply with a configure event telling + the expected new surface size. The operation is completed + on the next buffer attach to this surface. - A maximized surface typically fills the entire output it is - bound to, except for desktop elements such as panels. This is - the main difference between a maximized shell surface and a - fullscreen shell surface. + A maximized surface typically fills the entire output it is + bound to, except for desktop elements such as panels. This is + the main difference between a maximized shell surface and a + fullscreen shell surface. - The details depend on the compositor implementation. + The details depend on the compositor implementation. + summary="output on which the surface is to be maximized"/> - Set a short title for the surface. + Set a short title for the surface. - This string may be used to identify the surface in a task bar, - window list, or other user interface elements provided by the - compositor. + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. - The string must be encoded in UTF-8. + The string must be encoded in UTF-8. - Set a class for the surface. + Set a class for the surface. - The surface class identifies the general class of applications - to which the surface belongs. A common convention is to use the - file name (or the full path if it is a non-standard location) of - the application's .desktop file as the class. + The surface class identifies the general class of applications + to which the surface belongs. A common convention is to use the + file name (or the full path if it is a non-standard location) of + the application's .desktop file as the class. - Ping a client to check if it is receiving events and sending - requests. A client is expected to reply with a pong request. + Ping a client to check if it is receiving events and sending + requests. A client is expected to reply with a pong request. - The configure event asks the client to resize its surface. + The configure event asks the client to resize its surface. - The size is a hint, in the sense that the client is free to - ignore it if it doesn't resize, pick a smaller size (to - satisfy aspect ratio or resize in steps of NxM pixels). + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). - The edges parameter provides a hint about how the surface - was resized. The client may use this information to decide - how to adjust its content to the new size (e.g. a scrolling - area might adjust its content position to leave the viewable - content unmoved). + The edges parameter provides a hint about how the surface + was resized. The client may use this information to decide + how to adjust its content to the new size (e.g. a scrolling + area might adjust its content position to leave the viewable + content unmoved). - The client is free to dismiss all but the last configure - event it received. + The client is free to dismiss all but the last configure + event it received. - The width and height arguments specify the size of the window - in surface-local coordinates. + The width and height arguments specify the size of the window + in surface-local coordinates. @@ -1408,9 +1408,9 @@ - The popup_done event is sent out when a popup grab is broken, - that is, when the user clicks a surface that doesn't belong - to the client owning the popup surface. + The popup_done event is sent out when a popup grab is broken, + that is, when the user clicks a surface that doesn't belong + to the client owning the popup surface. @@ -1463,119 +1463,119 @@ - These errors can be emitted in response to wl_surface requests. + These errors can be emitted in response to wl_surface requests. + summary="surface was destroyed before its role object"/> - Deletes the surface and invalidates its object ID. + Deletes the surface and invalidates its object ID. - Set a buffer as the content of this surface. + Set a buffer as the content of this surface. - The new size of the surface is calculated based on the buffer - size transformed by the inverse buffer_transform and the - inverse buffer_scale. This means that at commit time the supplied - buffer size must be an integer multiple of the buffer_scale. If - that's not the case, an invalid_size error is sent. + The new size of the surface is calculated based on the buffer + size transformed by the inverse buffer_transform and the + inverse buffer_scale. This means that at commit time the supplied + buffer size must be an integer multiple of the buffer_scale. If + that's not the case, an invalid_size error is sent. - The x and y arguments specify the location of the new pending - buffer's upper left corner, relative to the current buffer's upper - left corner, in surface-local coordinates. In other words, the - x and y, combined with the new surface size define in which - directions the surface's size changes. Setting anything other than 0 - as x and y arguments is discouraged, and should instead be replaced - with using the separate wl_surface.offset request. + The x and y arguments specify the location of the new pending + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface-local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. Setting anything other than 0 + as x and y arguments is discouraged, and should instead be replaced + with using the separate wl_surface.offset request. - When the bound wl_surface version is 5 or higher, passing any - non-zero x or y is a protocol violation, and will result in an - 'invalid_offset' error being raised. The x and y arguments are ignored - and do not change the pending state. To achieve equivalent semantics, - use wl_surface.offset. + When the bound wl_surface version is 5 or higher, passing any + non-zero x or y is a protocol violation, and will result in an + 'invalid_offset' error being raised. The x and y arguments are ignored + and do not change the pending state. To achieve equivalent semantics, + use wl_surface.offset. - Surface contents are double-buffered state, see wl_surface.commit. + Surface contents are double-buffered state, see wl_surface.commit. - The initial surface contents are void; there is no content. - wl_surface.attach assigns the given wl_buffer as the pending - wl_buffer. wl_surface.commit makes the pending wl_buffer the new - surface contents, and the size of the surface becomes the size - calculated from the wl_buffer, as described above. After commit, - there is no pending buffer until the next attach. + The initial surface contents are void; there is no content. + wl_surface.attach assigns the given wl_buffer as the pending + wl_buffer. wl_surface.commit makes the pending wl_buffer the new + surface contents, and the size of the surface becomes the size + calculated from the wl_buffer, as described above. After commit, + there is no pending buffer until the next attach. - Committing a pending wl_buffer allows the compositor to read the - pixels in the wl_buffer. The compositor may access the pixels at - any time after the wl_surface.commit request. When the compositor - will not access the pixels anymore, it will send the - wl_buffer.release event. Only after receiving wl_buffer.release, - the client may reuse the wl_buffer. A wl_buffer that has been - attached and then replaced by another attach instead of committed - will not receive a release event, and is not used by the - compositor. + Committing a pending wl_buffer allows the compositor to read the + pixels in the wl_buffer. The compositor may access the pixels at + any time after the wl_surface.commit request. When the compositor + will not access the pixels anymore, it will send the + wl_buffer.release event. Only after receiving wl_buffer.release, + the client may reuse the wl_buffer. A wl_buffer that has been + attached and then replaced by another attach instead of committed + will not receive a release event, and is not used by the + compositor. - If a pending wl_buffer has been committed to more than one wl_surface, - the delivery of wl_buffer.release events becomes undefined. A well - behaved client should not rely on wl_buffer.release events in this - case. Alternatively, a client could create multiple wl_buffer objects - from the same backing storage or use a protocol extension providing - per-commit release notifications. + If a pending wl_buffer has been committed to more than one wl_surface, + the delivery of wl_buffer.release events becomes undefined. A well + behaved client should not rely on wl_buffer.release events in this + case. Alternatively, a client could create multiple wl_buffer objects + from the same backing storage or use a protocol extension providing + per-commit release notifications. - Destroying the wl_buffer after wl_buffer.release does not change - the surface contents. Destroying the wl_buffer before wl_buffer.release - is allowed as long as the underlying buffer storage isn't re-used (this - can happen e.g. on client process termination). However, if the client - destroys the wl_buffer before receiving the wl_buffer.release event and - mutates the underlying buffer storage, the surface contents become - undefined immediately. + Destroying the wl_buffer after wl_buffer.release does not change + the surface contents. Destroying the wl_buffer before wl_buffer.release + is allowed as long as the underlying buffer storage isn't re-used (this + can happen e.g. on client process termination). However, if the client + destroys the wl_buffer before receiving the wl_buffer.release event and + mutates the underlying buffer storage, the surface contents become + undefined immediately. - If wl_surface.attach is sent with a NULL wl_buffer, the - following wl_surface.commit will remove the surface content. + If wl_surface.attach is sent with a NULL wl_buffer, the + following wl_surface.commit will remove the surface content. - If a pending wl_buffer has been destroyed, the result is not specified. - Many compositors are known to remove the surface content on the following - wl_surface.commit, but this behaviour is not universal. Clients seeking to - maximise compatibility should not destroy pending buffers and should - ensure that they explicitly remove content from surfaces, even after - destroying buffers. + If a pending wl_buffer has been destroyed, the result is not specified. + Many compositors are known to remove the surface content on the following + wl_surface.commit, but this behaviour is not universal. Clients seeking to + maximise compatibility should not destroy pending buffers and should + ensure that they explicitly remove content from surfaces, even after + destroying buffers. + summary="buffer of surface contents"/> - This request is used to describe the regions where the pending - buffer is different from the current surface contents, and where - the surface therefore needs to be repainted. The compositor - ignores the parts of the damage that fall outside of the surface. + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. - Damage is double-buffered state, see wl_surface.commit. + Damage is double-buffered state, see wl_surface.commit. - The damage rectangle is specified in surface-local coordinates, - where x and y specify the upper left corner of the damage rectangle. + The damage rectangle is specified in surface-local coordinates, + where x and y specify the upper left corner of the damage rectangle. - The initial value for pending damage is empty: no damage. - wl_surface.damage adds pending damage: the new pending damage - is the union of old pending damage and the given rectangle. + The initial value for pending damage is empty: no damage. + wl_surface.damage adds pending damage: the new pending damage + is the union of old pending damage and the given rectangle. - wl_surface.commit assigns pending damage as the current damage, - and clears pending damage. The server will clear the current - damage as it repaints the surface. + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. - Note! New clients should not use this request. Instead damage can be - posted with wl_surface.damage_buffer which uses buffer coordinates - instead of surface coordinates. + Note! New clients should not use this request. Instead damage can be + posted with wl_surface.damage_buffer which uses buffer coordinates + instead of surface coordinates. @@ -1585,175 +1585,175 @@ - Request a notification when it is a good time to start drawing a new - frame, by creating a frame callback. This is useful for throttling - redrawing operations, and driving animations. + Request a notification when it is a good time to start drawing a new + frame, by creating a frame callback. This is useful for throttling + redrawing operations, and driving animations. - When a client is animating on a wl_surface, it can use the 'frame' - request to get notified when it is a good time to draw and commit the - next frame of animation. If the client commits an update earlier than - that, it is likely that some updates will not make it to the display, - and the client is wasting resources by drawing too often. + When a client is animating on a wl_surface, it can use the 'frame' + request to get notified when it is a good time to draw and commit the + next frame of animation. If the client commits an update earlier than + that, it is likely that some updates will not make it to the display, + and the client is wasting resources by drawing too often. - The frame request will take effect on the next wl_surface.commit. - The notification will only be posted for one frame unless - requested again. For a wl_surface, the notifications are posted in - the order the frame requests were committed. + The frame request will take effect on the next wl_surface.commit. + The notification will only be posted for one frame unless + requested again. For a wl_surface, the notifications are posted in + the order the frame requests were committed. - The server must send the notifications so that a client - will not send excessive updates, while still allowing - the highest possible update rate for clients that wait for the reply - before drawing again. The server should give some time for the client - to draw and commit after sending the frame callback events to let it - hit the next output refresh. + The server must send the notifications so that a client + will not send excessive updates, while still allowing + the highest possible update rate for clients that wait for the reply + before drawing again. The server should give some time for the client + to draw and commit after sending the frame callback events to let it + hit the next output refresh. - A server should avoid signaling the frame callbacks if the - surface is not visible in any way, e.g. the surface is off-screen, - or completely obscured by other opaque surfaces. + A server should avoid signaling the frame callbacks if the + surface is not visible in any way, e.g. the surface is off-screen, + or completely obscured by other opaque surfaces. - The object returned by this request will be destroyed by the - compositor after the callback is fired and as such the client must not - attempt to use it after that point. + The object returned by this request will be destroyed by the + compositor after the callback is fired and as such the client must not + attempt to use it after that point. - The callback_data passed in the callback is the current time, in - milliseconds, with an undefined base. + The callback_data passed in the callback is the current time, in + milliseconds, with an undefined base. - This request sets the region of the surface that contains - opaque content. + This request sets the region of the surface that contains + opaque content. - The opaque region is an optimization hint for the compositor - that lets it optimize the redrawing of content behind opaque - regions. Setting an opaque region is not required for correct - behaviour, but marking transparent content as opaque will result - in repaint artifacts. + The opaque region is an optimization hint for the compositor + that lets it optimize the redrawing of content behind opaque + regions. Setting an opaque region is not required for correct + behaviour, but marking transparent content as opaque will result + in repaint artifacts. - The opaque region is specified in surface-local coordinates. + The opaque region is specified in surface-local coordinates. - The compositor ignores the parts of the opaque region that fall - outside of the surface. + The compositor ignores the parts of the opaque region that fall + outside of the surface. - Opaque region is double-buffered state, see wl_surface.commit. + Opaque region is double-buffered state, see wl_surface.commit. - wl_surface.set_opaque_region changes the pending opaque region. - wl_surface.commit copies the pending region to the current region. - Otherwise, the pending and current regions are never changed. + wl_surface.set_opaque_region changes the pending opaque region. + wl_surface.commit copies the pending region to the current region. + Otherwise, the pending and current regions are never changed. - The initial value for an opaque region is empty. Setting the pending - opaque region has copy semantics, and the wl_region object can be - destroyed immediately. A NULL wl_region causes the pending opaque - region to be set to empty. + The initial value for an opaque region is empty. Setting the pending + opaque region has copy semantics, and the wl_region object can be + destroyed immediately. A NULL wl_region causes the pending opaque + region to be set to empty. + summary="opaque region of the surface"/> - This request sets the region of the surface that can receive - pointer and touch events. + This request sets the region of the surface that can receive + pointer and touch events. - Input events happening outside of this region will try the next - surface in the server surface stack. The compositor ignores the - parts of the input region that fall outside of the surface. + Input events happening outside of this region will try the next + surface in the server surface stack. The compositor ignores the + parts of the input region that fall outside of the surface. - The input region is specified in surface-local coordinates. + The input region is specified in surface-local coordinates. - Input region is double-buffered state, see wl_surface.commit. + Input region is double-buffered state, see wl_surface.commit. - wl_surface.set_input_region changes the pending input region. - wl_surface.commit copies the pending region to the current region. - Otherwise the pending and current regions are never changed, - except cursor and icon surfaces are special cases, see - wl_pointer.set_cursor and wl_data_device.start_drag. + wl_surface.set_input_region changes the pending input region. + wl_surface.commit copies the pending region to the current region. + Otherwise the pending and current regions are never changed, + except cursor and icon surfaces are special cases, see + wl_pointer.set_cursor and wl_data_device.start_drag. - The initial value for an input region is infinite. That means the - whole surface will accept input. Setting the pending input region - has copy semantics, and the wl_region object can be destroyed - immediately. A NULL wl_region causes the input region to be set - to infinite. + The initial value for an input region is infinite. That means the + whole surface will accept input. Setting the pending input region + has copy semantics, and the wl_region object can be destroyed + immediately. A NULL wl_region causes the input region to be set + to infinite. + summary="input region of the surface"/> - Surface state (input, opaque, and damage regions, attached buffers, - etc.) is double-buffered. Protocol requests modify the pending state, - as opposed to the active state in use by the compositor. + Surface state (input, opaque, and damage regions, attached buffers, + etc.) is double-buffered. Protocol requests modify the pending state, + as opposed to the active state in use by the compositor. - All requests that need a commit to become effective are documented - to affect double-buffered state. + All requests that need a commit to become effective are documented + to affect double-buffered state. - Other interfaces may add further double-buffered surface state. + Other interfaces may add further double-buffered surface state. - A commit request atomically creates a Content Update (CU) from the - pending state, even if the pending state has not been touched. The - content update is placed at the end of a per-surface queue until it - becomes active. After commit, the new pending state is as documented for - each related request. + A commit request atomically creates a Content Update (CU) from the + pending state, even if the pending state has not been touched. The + content update is placed at the end of a per-surface queue until it + becomes active. After commit, the new pending state is as documented for + each related request. - A CU is either a Desync Content Update (DCU) or a Sync Content Update - (SCU). If the surface is effectively synchronized at the commit request, - it is a SCU, otherwise a DCU. + A CU is either a Desync Content Update (DCU) or a Sync Content Update + (SCU). If the surface is effectively synchronized at the commit request, + it is a SCU, otherwise a DCU. - When a surface transitions from effectively synchronized to effectively - desynchronized, all SCUs in its queue which are not reachable by any - DCU become DCUs and dependency edges from outside the queue to these CUs - are removed. + When a surface transitions from effectively synchronized to effectively + desynchronized, all SCUs in its queue which are not reachable by any + DCU become DCUs and dependency edges from outside the queue to these CUs + are removed. - See wl_subsurface for the definition of 'effectively synchronized' and - 'effectively desynchronized'. + See wl_subsurface for the definition of 'effectively synchronized' and + 'effectively desynchronized'. - When a CU is placed in the queue, the CU has a dependency on the CU in - front of it and to the SCU at end of the queue of every direct child - surface if that SCU exists and does not have another dependent. This can - form a directed acyclic graph of CUs with dependencies as edges. + When a CU is placed in the queue, the CU has a dependency on the CU in + front of it and to the SCU at end of the queue of every direct child + surface if that SCU exists and does not have another dependent. This can + form a directed acyclic graph of CUs with dependencies as edges. - In addition to surface state, the CU can have constraints that must be - satisfied before it can be applied. Other interfaces may add CU - constraints. + In addition to surface state, the CU can have constraints that must be + satisfied before it can be applied. Other interfaces may add CU + constraints. - All DCUs which do not have a SCU in front of themselves in their queue, - are candidates. If the graph that's reachable by a candidate does not - have any unsatisfied constraints, the entire graph must be applied - atomically. + All DCUs which do not have a SCU in front of themselves in their queue, + are candidates. If the graph that's reachable by a candidate does not + have any unsatisfied constraints, the entire graph must be applied + atomically. - When a CU is applied, the wl_buffer is applied before all other state. - This means that all coordinates in double-buffered state are relative to - the newly attached wl_buffers, except for wl_surface.attach itself. If - there is no newly attached wl_buffer, the coordinates are relative to - the previous content update. + When a CU is applied, the wl_buffer is applied before all other state. + This means that all coordinates in double-buffered state are relative to + the newly attached wl_buffers, except for wl_surface.attach itself. If + there is no newly attached wl_buffer, the coordinates are relative to + the previous content update. - This is emitted whenever a surface's creation, movement, or resizing - results in some part of it being within the scanout region of an - output. + This is emitted whenever a surface's creation, movement, or resizing + results in some part of it being within the scanout region of an + output. - Note that a surface may be overlapping with zero or more outputs. + Note that a surface may be overlapping with zero or more outputs. - This is emitted whenever a surface's creation, movement, or resizing - results in it no longer having any part of it within the scanout region - of an output. + This is emitted whenever a surface's creation, movement, or resizing + results in it no longer having any part of it within the scanout region + of an output. - Clients should not use the number of outputs the surface is on for frame - throttling purposes. The surface might be hidden even if no leave event - has been sent, and the compositor might expect new surface content - updates even if no enter event has been sent. The frame event should be - used instead. + Clients should not use the number of outputs the surface is on for frame + throttling purposes. The surface might be hidden even if no leave event + has been sent, and the compositor might expect new surface content + updates even if no enter event has been sent. The frame event should be + used instead. @@ -1762,109 +1762,109 @@ - This request sets the transformation that the client has already applied - to the content of the buffer. The accepted values for the transform - parameter are the values for wl_output.transform. + This request sets the transformation that the client has already applied + to the content of the buffer. The accepted values for the transform + parameter are the values for wl_output.transform. - The compositor applies the inverse of this transformation whenever it - uses the buffer contents. + The compositor applies the inverse of this transformation whenever it + uses the buffer contents. - Buffer transform is double-buffered state, see wl_surface.commit. + Buffer transform is double-buffered state, see wl_surface.commit. - A newly created surface has its buffer transformation set to normal. + A newly created surface has its buffer transformation set to normal. - wl_surface.set_buffer_transform changes the pending buffer - transformation. wl_surface.commit copies the pending buffer - transformation to the current one. Otherwise, the pending and current - values are never changed. + wl_surface.set_buffer_transform changes the pending buffer + transformation. wl_surface.commit copies the pending buffer + transformation to the current one. Otherwise, the pending and current + values are never changed. - The purpose of this request is to allow clients to render content - according to the output transform, thus permitting the compositor to - use certain optimizations even if the display is rotated. Using - hardware overlays and scanning out a client buffer for fullscreen - surfaces are examples of such optimizations. Those optimizations are - highly dependent on the compositor implementation, so the use of this - request should be considered on a case-by-case basis. + The purpose of this request is to allow clients to render content + according to the output transform, thus permitting the compositor to + use certain optimizations even if the display is rotated. Using + hardware overlays and scanning out a client buffer for fullscreen + surfaces are examples of such optimizations. Those optimizations are + highly dependent on the compositor implementation, so the use of this + request should be considered on a case-by-case basis. - Note that if the transform value includes 90 or 270 degree rotation, - the width of the buffer will become the surface height and the height - of the buffer will become the surface width. + Note that if the transform value includes 90 or 270 degree rotation, + the width of the buffer will become the surface height and the height + of the buffer will become the surface width. - If transform is not one of the values from the - wl_output.transform enum the invalid_transform protocol error - is raised. + If transform is not one of the values from the + wl_output.transform enum the invalid_transform protocol error + is raised. + summary="transform for interpreting buffer contents"/> - This request sets an optional scaling factor on how the compositor - interprets the contents of the buffer attached to the window. + This request sets an optional scaling factor on how the compositor + interprets the contents of the buffer attached to the window. - Buffer scale is double-buffered state, see wl_surface.commit. + Buffer scale is double-buffered state, see wl_surface.commit. - A newly created surface has its buffer scale set to 1. + A newly created surface has its buffer scale set to 1. - wl_surface.set_buffer_scale changes the pending buffer scale. - wl_surface.commit copies the pending buffer scale to the current one. - Otherwise, the pending and current values are never changed. + wl_surface.set_buffer_scale changes the pending buffer scale. + wl_surface.commit copies the pending buffer scale to the current one. + Otherwise, the pending and current values are never changed. - The purpose of this request is to allow clients to supply higher - resolution buffer data for use on high resolution outputs. It is - intended that you pick the same buffer scale as the scale of the - output that the surface is displayed on. This means the compositor - can avoid scaling when rendering the surface on that output. + The purpose of this request is to allow clients to supply higher + resolution buffer data for use on high resolution outputs. It is + intended that you pick the same buffer scale as the scale of the + output that the surface is displayed on. This means the compositor + can avoid scaling when rendering the surface on that output. - Note that if the scale is larger than 1, then you have to attach - a buffer that is larger (by a factor of scale in each dimension) - than the desired surface size. + Note that if the scale is larger than 1, then you have to attach + a buffer that is larger (by a factor of scale in each dimension) + than the desired surface size. - If scale is not greater than 0 the invalid_scale protocol error is - raised. + If scale is not greater than 0 the invalid_scale protocol error is + raised. + summary="scale for interpreting buffer contents"/> - This request is used to describe the regions where the pending - buffer is different from the current surface contents, and where - the surface therefore needs to be repainted. The compositor - ignores the parts of the damage that fall outside of the surface. + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. - Damage is double-buffered state, see wl_surface.commit. + Damage is double-buffered state, see wl_surface.commit. - The damage rectangle is specified in buffer coordinates, - where x and y specify the upper left corner of the damage rectangle. + The damage rectangle is specified in buffer coordinates, + where x and y specify the upper left corner of the damage rectangle. - The initial value for pending damage is empty: no damage. - wl_surface.damage_buffer adds pending damage: the new pending - damage is the union of old pending damage and the given rectangle. + The initial value for pending damage is empty: no damage. + wl_surface.damage_buffer adds pending damage: the new pending + damage is the union of old pending damage and the given rectangle. - wl_surface.commit assigns pending damage as the current damage, - and clears pending damage. The server will clear the current - damage as it repaints the surface. + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. - This request differs from wl_surface.damage in only one way - it - takes damage in buffer coordinates instead of surface-local - coordinates. While this generally is more intuitive than surface - coordinates, it is especially desirable when using wp_viewport - or when a drawing library (like EGL) is unaware of buffer scale - and buffer transform. + This request differs from wl_surface.damage in only one way - it + takes damage in buffer coordinates instead of surface-local + coordinates. While this generally is more intuitive than surface + coordinates, it is especially desirable when using wp_viewport + or when a drawing library (like EGL) is unaware of buffer scale + and buffer transform. - Note: Because buffer transformation changes and damage requests may - be interleaved in the protocol stream, it is impossible to determine - the actual mapping between surface and buffer damage until - wl_surface.commit time. Therefore, compositors wishing to take both - kinds of damage into account will have to accumulate damage from the - two requests separately and only transform from one to the other - after receiving the wl_surface.commit. + Note: Because buffer transformation changes and damage requests may + be interleaved in the protocol stream, it is impossible to determine + the actual mapping between surface and buffer damage until + wl_surface.commit time. Therefore, compositors wishing to take both + kinds of damage into account will have to accumulate damage from the + two requests separately and only transform from one to the other + after receiving the wl_surface.commit. @@ -1876,21 +1876,21 @@ - The x and y arguments specify the location of the new pending - buffer's upper left corner, relative to the current buffer's upper - left corner, in surface-local coordinates. In other words, the - x and y, combined with the new surface size define in which - directions the surface's size changes. + The x and y arguments specify the location of the new pending + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface-local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. - The exact semantics of wl_surface.offset are role-specific. Refer to - the documentation of specific roles for more information. + The exact semantics of wl_surface.offset are role-specific. Refer to + the documentation of specific roles for more information. - Surface location offset is double-buffered state, see - wl_surface.commit. + Surface location offset is double-buffered state, see + wl_surface.commit. - This request is semantically equivalent to and the replaces the x and y - arguments in the wl_surface.attach request in wl_surface versions prior - to 5. See wl_surface.attach for details. + This request is semantically equivalent to and the replaces the x and y + arguments in the wl_surface.attach request in wl_surface versions prior + to 5. See wl_surface.attach for details. @@ -1900,36 +1900,36 @@ - This event indicates the preferred buffer scale for this surface. It is - sent whenever the compositor's preference changes. + This event indicates the preferred buffer scale for this surface. It is + sent whenever the compositor's preference changes. - Before receiving this event the preferred buffer scale for this surface - is 1. + Before receiving this event the preferred buffer scale for this surface + is 1. - It is intended that scaling aware clients use this event to scale their - content and use wl_surface.set_buffer_scale to indicate the scale they - have rendered with. This allows clients to supply a higher detail - buffer. + It is intended that scaling aware clients use this event to scale their + content and use wl_surface.set_buffer_scale to indicate the scale they + have rendered with. This allows clients to supply a higher detail + buffer. - The compositor shall emit a scale value greater than 0. + The compositor shall emit a scale value greater than 0. - This event indicates the preferred buffer transform for this surface. - It is sent whenever the compositor's preference changes. + This event indicates the preferred buffer transform for this surface. + It is sent whenever the compositor's preference changes. - Before receiving this event the preferred buffer transform for this - surface is normal. + Before receiving this event the preferred buffer transform for this + surface is normal. - Applying this transformation to the surface buffer contents and using - wl_surface.set_buffer_transform might allow the compositor to use the - surface buffer more efficiently. + Applying this transformation to the surface buffer contents and using + wl_surface.set_buffer_transform might allow the compositor to use the + surface buffer more efficiently. + summary="preferred transform"/> @@ -1943,8 +1943,8 @@ - This is a bitmask of capabilities this seat has; if a member is - set, then it is present on the seat. + This is a bitmask of capabilities this seat has; if a member is + set, then it is present on the seat. @@ -1953,81 +1953,81 @@ - These errors can be emitted in response to wl_seat requests. + These errors can be emitted in response to wl_seat requests. + summary="get_pointer, get_keyboard or get_touch called on seat without the matching capability"/> - This is sent on binding to the seat global or whenever a seat gains - or loses the pointer, keyboard or touch capabilities. - The argument is a capability enum containing the complete set of - capabilities this seat has. + This is sent on binding to the seat global or whenever a seat gains + or loses the pointer, keyboard or touch capabilities. + The argument is a capability enum containing the complete set of + capabilities this seat has. - When the pointer capability is added, a client may create a - wl_pointer object using the wl_seat.get_pointer request. This object - will receive pointer events until the capability is removed in the - future. + When the pointer capability is added, a client may create a + wl_pointer object using the wl_seat.get_pointer request. This object + will receive pointer events until the capability is removed in the + future. - When the pointer capability is removed, a client should destroy the - wl_pointer objects associated with the seat where the capability was - removed, using the wl_pointer.release request. No further pointer - events will be received on these objects. + When the pointer capability is removed, a client should destroy the + wl_pointer objects associated with the seat where the capability was + removed, using the wl_pointer.release request. No further pointer + events will be received on these objects. - In some compositors, if a seat regains the pointer capability and a - client has a previously obtained wl_pointer object of version 4 or - less, that object may start sending pointer events again. This - behavior is considered a misinterpretation of the intended behavior - and must not be relied upon by the client. wl_pointer objects of - version 5 or later must not send events if created before the most - recent event notifying the client of an added pointer capability. + In some compositors, if a seat regains the pointer capability and a + client has a previously obtained wl_pointer object of version 4 or + less, that object may start sending pointer events again. This + behavior is considered a misinterpretation of the intended behavior + and must not be relied upon by the client. wl_pointer objects of + version 5 or later must not send events if created before the most + recent event notifying the client of an added pointer capability. - The above behavior also applies to wl_keyboard and wl_touch with the - keyboard and touch capabilities, respectively. + The above behavior also applies to wl_keyboard and wl_touch with the + keyboard and touch capabilities, respectively. - The ID provided will be initialized to the wl_pointer interface - for this seat. + The ID provided will be initialized to the wl_pointer interface + for this seat. - This request only takes effect if the seat has the pointer - capability, or has had the pointer capability in the past. - It is a protocol violation to issue this request on a seat that has - never had the pointer capability. The missing_capability error will - be sent in this case. + This request only takes effect if the seat has the pointer + capability, or has had the pointer capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the pointer capability. The missing_capability error will + be sent in this case. - The ID provided will be initialized to the wl_keyboard interface - for this seat. + The ID provided will be initialized to the wl_keyboard interface + for this seat. - This request only takes effect if the seat has the keyboard - capability, or has had the keyboard capability in the past. - It is a protocol violation to issue this request on a seat that has - never had the keyboard capability. The missing_capability error will - be sent in this case. + This request only takes effect if the seat has the keyboard + capability, or has had the keyboard capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the keyboard capability. The missing_capability error will + be sent in this case. - The ID provided will be initialized to the wl_touch interface - for this seat. + The ID provided will be initialized to the wl_touch interface + for this seat. - This request only takes effect if the seat has the touch - capability, or has had the touch capability in the past. - It is a protocol violation to issue this request on a seat that has - never had the touch capability. The missing_capability error will - be sent in this case. + This request only takes effect if the seat has the touch + capability, or has had the touch capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the touch capability. The missing_capability error will + be sent in this case. @@ -2036,22 +2036,22 @@ - In a multi-seat configuration the seat name can be used by clients to - help identify which physical devices the seat represents. + In a multi-seat configuration the seat name can be used by clients to + help identify which physical devices the seat represents. - The seat name is a UTF-8 string with no convention defined for its - contents. Each name is unique among all wl_seat globals. The name is - only guaranteed to be unique for the current compositor instance. + The seat name is a UTF-8 string with no convention defined for its + contents. Each name is unique among all wl_seat globals. The name is + only guaranteed to be unique for the current compositor instance. - The same seat names are used for all clients. Thus, the name can be - shared across processes to refer to a specific wl_seat global. + The same seat names are used for all clients. Thus, the name can be + shared across processes to refer to a specific wl_seat global. - The name event is sent after binding to the seat global, and should be sent - before announcing capabilities. This event only sent once per seat object, - and the name does not change over the lifetime of the wl_seat global. + The name event is sent after binding to the seat global, and should be sent + before announcing capabilities. This event only sent once per seat object, + and the name does not change over the lifetime of the wl_seat global. - Compositors may re-use the same seat name if the wl_seat global is - destroyed and re-created later. + Compositors may re-use the same seat name if the wl_seat global is + destroyed and re-created later. @@ -2060,8 +2060,8 @@ - Using this request a client can tell the server that it is not going to - use the seat object anymore. + Using this request a client can tell the server that it is not going to + use the seat object anymore. @@ -2085,55 +2085,55 @@ - Set the pointer surface, i.e., the surface that contains the - pointer image (cursor). This request gives the surface the role - of a cursor. If the surface already has another role, it raises - a protocol error. + Set the pointer surface, i.e., the surface that contains the + pointer image (cursor). This request gives the surface the role + of a cursor. If the surface already has another role, it raises + a protocol error. - The cursor actually changes only if the pointer - focus for this device is one of the requesting client's surfaces - or the surface parameter is the current pointer surface. If - there was a previous surface set with this request it is - replaced. If surface is NULL, the pointer image is hidden. + The cursor actually changes only if the pointer + focus for this device is one of the requesting client's surfaces + or the surface parameter is the current pointer surface. If + there was a previous surface set with this request it is + replaced. If surface is NULL, the pointer image is hidden. - The parameters hotspot_x and hotspot_y define the position of - the pointer surface relative to the pointer location. Its - top-left corner is always at (x, y) - (hotspot_x, hotspot_y), - where (x, y) are the coordinates of the pointer location, in - surface-local coordinates. + The parameters hotspot_x and hotspot_y define the position of + the pointer surface relative to the pointer location. Its + top-left corner is always at (x, y) - (hotspot_x, hotspot_y), + where (x, y) are the coordinates of the pointer location, in + surface-local coordinates. - On wl_surface.offset requests to the pointer surface, hotspot_x - and hotspot_y are decremented by the x and y parameters - passed to the request. The offset must be applied by - wl_surface.commit as usual. + On wl_surface.offset requests to the pointer surface, hotspot_x + and hotspot_y are decremented by the x and y parameters + passed to the request. The offset must be applied by + wl_surface.commit as usual. - The hotspot can also be updated by passing the currently set - pointer surface to this request with new values for hotspot_x - and hotspot_y. + The hotspot can also be updated by passing the currently set + pointer surface to this request with new values for hotspot_x + and hotspot_y. - The input region is ignored for wl_surfaces with the role of - a cursor. When the use as a cursor ends, the wl_surface is - unmapped. + The input region is ignored for wl_surfaces with the role of + a cursor. When the use as a cursor ends, the wl_surface is + unmapped. - The serial parameter must match the latest wl_pointer.enter - serial number sent to the client. Otherwise the request will be - ignored. + The serial parameter must match the latest wl_pointer.enter + serial number sent to the client. Otherwise the request will be + ignored. + summary="pointer surface"/> - Notification that this seat's pointer is focused on a certain - surface. + Notification that this seat's pointer is focused on a certain + surface. - When a seat's focus enters a surface, the pointer image - is undefined and a client should respond to this event by setting - an appropriate pointer image with the set_cursor request. + When a seat's focus enters a surface, the pointer image + is undefined and a client should respond to this event by setting + an appropriate pointer image with the set_cursor request. @@ -2143,11 +2143,11 @@ - Notification that this seat's pointer is no longer focused on - a certain surface. + Notification that this seat's pointer is no longer focused on + a certain surface. - The leave notification is sent before the enter notification - for the new focus. + The leave notification is sent before the enter notification + for the new focus. @@ -2155,9 +2155,9 @@ - Notification of pointer location change. The arguments - surface_x and surface_y are the location relative to the - focused surface. + Notification of pointer location change. The arguments + surface_x and surface_y are the location relative to the + focused surface. @@ -2166,8 +2166,8 @@ - Describes the physical state of a button that produced the button - event. + Describes the physical state of a button that produced the button + event. @@ -2175,20 +2175,20 @@ - Mouse button click and release notifications. + Mouse button click and release notifications. - The location of the click is given by the last motion or - enter event. - The time argument is a timestamp with millisecond - granularity, with an undefined base. + The location of the click is given by the last motion or + enter event. + The time argument is a timestamp with millisecond + granularity, with an undefined base. - The button is a button code as defined in the Linux kernel's - linux/input-event-codes.h header file, e.g. BTN_LEFT. + The button is a button code as defined in the Linux kernel's + linux/input-event-codes.h header file, e.g. BTN_LEFT. - Any 16-bit button code value is reserved for future additions to the - kernel's event code list. All other button codes above 0xFFFF are - currently undefined but may be used in future versions of this - protocol. + Any 16-bit button code value is reserved for future additions to the + kernel's event code list. All other button codes above 0xFFFF are + currently undefined but may be used in future versions of this + protocol. @@ -2198,7 +2198,7 @@ - Describes the axis types of scroll events. + Describes the axis types of scroll events. @@ -2206,22 +2206,22 @@ - Scroll and other axis notifications. + Scroll and other axis notifications. - For scroll events (vertical and horizontal scroll axes), the - value parameter is the length of a vector along the specified - axis in a coordinate space identical to those of motion events, - representing a relative movement along the specified axis. + For scroll events (vertical and horizontal scroll axes), the + value parameter is the length of a vector along the specified + axis in a coordinate space identical to those of motion events, + representing a relative movement along the specified axis. - For devices that support movements non-parallel to axes multiple - axis events will be emitted. + For devices that support movements non-parallel to axes multiple + axis events will be emitted. - When applicable, for example for touch pads, the server can - choose to emit scroll events where the motion vector is - equivalent to a motion event vector. + When applicable, for example for touch pads, the server can + choose to emit scroll events where the motion vector is + equivalent to a motion event vector. - When applicable, a client can transform its content relative to the - scroll distance. + When applicable, a client can transform its content relative to the + scroll distance. @@ -2232,11 +2232,11 @@ - Using this request a client can tell the server that it is not going to - use the pointer object anymore. + Using this request a client can tell the server that it is not going to + use the pointer object anymore. - This request destroys the pointer proxy object, so clients must not call - wl_pointer_destroy() after using this request. + This request destroys the pointer proxy object, so clients must not call + wl_pointer_destroy() after using this request. @@ -2244,61 +2244,61 @@ - Indicates the end of a set of events that logically belong together. - A client is expected to accumulate the data in all events within the - frame before proceeding. + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. - All wl_pointer events before a wl_pointer.frame event belong - logically together. For example, in a diagonal scroll motion the - compositor will send an optional wl_pointer.axis_source event, two - wl_pointer.axis events (horizontal and vertical) and finally a - wl_pointer.frame event. The client may use this information to - calculate a diagonal vector for scrolling. + All wl_pointer events before a wl_pointer.frame event belong + logically together. For example, in a diagonal scroll motion the + compositor will send an optional wl_pointer.axis_source event, two + wl_pointer.axis events (horizontal and vertical) and finally a + wl_pointer.frame event. The client may use this information to + calculate a diagonal vector for scrolling. - When multiple wl_pointer.axis events occur within the same frame, - the motion vector is the combined motion of all events. - When a wl_pointer.axis and a wl_pointer.axis_stop event occur within - the same frame, this indicates that axis movement in one axis has - stopped but continues in the other axis. - When multiple wl_pointer.axis_stop events occur within the same - frame, this indicates that these axes stopped in the same instance. + When multiple wl_pointer.axis events occur within the same frame, + the motion vector is the combined motion of all events. + When a wl_pointer.axis and a wl_pointer.axis_stop event occur within + the same frame, this indicates that axis movement in one axis has + stopped but continues in the other axis. + When multiple wl_pointer.axis_stop events occur within the same + frame, this indicates that these axes stopped in the same instance. - A wl_pointer.frame event is sent for every logical event group, - even if the group only contains a single wl_pointer event. - Specifically, a client may get a sequence: motion, frame, button, - frame, axis, frame, axis_stop, frame. + A wl_pointer.frame event is sent for every logical event group, + even if the group only contains a single wl_pointer event. + Specifically, a client may get a sequence: motion, frame, button, + frame, axis, frame, axis_stop, frame. - The wl_pointer.enter and wl_pointer.leave events are logical events - generated by the compositor and not the hardware. These events are - also grouped by a wl_pointer.frame. When a pointer moves from one - surface to another, a compositor should group the - wl_pointer.leave event within the same wl_pointer.frame. - However, a client must not rely on wl_pointer.leave and - wl_pointer.enter being in the same wl_pointer.frame. - Compositor-specific policies may require the wl_pointer.leave and - wl_pointer.enter event being split across multiple wl_pointer.frame - groups. + The wl_pointer.enter and wl_pointer.leave events are logical events + generated by the compositor and not the hardware. These events are + also grouped by a wl_pointer.frame. When a pointer moves from one + surface to another, a compositor should group the + wl_pointer.leave event within the same wl_pointer.frame. + However, a client must not rely on wl_pointer.leave and + wl_pointer.enter being in the same wl_pointer.frame. + Compositor-specific policies may require the wl_pointer.leave and + wl_pointer.enter event being split across multiple wl_pointer.frame + groups. - Describes the source types for axis events. This indicates to the - client how an axis event was physically generated; a client may - adjust the user interface accordingly. For example, scroll events - from a "finger" source may be in a smooth coordinate space with - kinetic scrolling whereas a "wheel" source may be in discrete steps - of a number of lines. + Describes the source types for axis events. This indicates to the + client how an axis event was physically generated; a client may + adjust the user interface accordingly. For example, scroll events + from a "finger" source may be in a smooth coordinate space with + kinetic scrolling whereas a "wheel" source may be in discrete steps + of a number of lines. - The "continuous" axis source is a device generating events in a - continuous coordinate space, but using something other than a - finger. One example for this source is button-based scrolling where - the vertical motion of a device is converted to scroll events while - a button is held down. + The "continuous" axis source is a device generating events in a + continuous coordinate space, but using something other than a + finger. One example for this source is button-based scrolling where + the vertical motion of a device is converted to scroll events while + a button is held down. - The "wheel tilt" axis source indicates that the actual device is a - wheel but the scroll event is not caused by a rotation but a - (usually sideways) tilt of the wheel. + The "wheel tilt" axis source indicates that the actual device is a + wheel but the scroll event is not caused by a rotation but a + (usually sideways) tilt of the wheel. @@ -2308,51 +2308,51 @@ - Source information for scroll and other axes. + Source information for scroll and other axes. - This event does not occur on its own. It is sent before a - wl_pointer.frame event and carries the source information for - all events within that frame. + This event does not occur on its own. It is sent before a + wl_pointer.frame event and carries the source information for + all events within that frame. - The source specifies how this event was generated. If the source is - wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be - sent when the user lifts the finger off the device. + The source specifies how this event was generated. If the source is + wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be + sent when the user lifts the finger off the device. - If the source is wl_pointer.axis_source.wheel, - wl_pointer.axis_source.wheel_tilt or - wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may - or may not be sent. Whether a compositor sends an axis_stop event - for these sources is hardware-specific and implementation-dependent; - clients must not rely on receiving an axis_stop event for these - scroll sources and should treat scroll sequences from these scroll - sources as unterminated by default. + If the source is wl_pointer.axis_source.wheel, + wl_pointer.axis_source.wheel_tilt or + wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may + or may not be sent. Whether a compositor sends an axis_stop event + for these sources is hardware-specific and implementation-dependent; + clients must not rely on receiving an axis_stop event for these + scroll sources and should treat scroll sequences from these scroll + sources as unterminated by default. - This event is optional. If the source is unknown for a particular - axis event sequence, no event is sent. - Only one wl_pointer.axis_source event is permitted per frame. + This event is optional. If the source is unknown for a particular + axis event sequence, no event is sent. + Only one wl_pointer.axis_source event is permitted per frame. - The order of wl_pointer.axis_discrete and wl_pointer.axis_source is - not guaranteed. + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. - Stop notification for scroll and other axes. + Stop notification for scroll and other axes. - For some wl_pointer.axis_source types, a wl_pointer.axis_stop event - is sent to notify a client that the axis sequence has terminated. - This enables the client to implement kinetic scrolling. - See the wl_pointer.axis_source documentation for information on when - this event may be generated. + For some wl_pointer.axis_source types, a wl_pointer.axis_stop event + is sent to notify a client that the axis sequence has terminated. + This enables the client to implement kinetic scrolling. + See the wl_pointer.axis_source documentation for information on when + this event may be generated. - Any wl_pointer.axis events with the same axis_source after this - event should be considered as the start of a new axis motion. + Any wl_pointer.axis events with the same axis_source after this + event should be considered as the start of a new axis motion. - The timestamp is to be interpreted identical to the timestamp in the - wl_pointer.axis event. The timestamp value may be the same as a - preceding wl_pointer.axis event. + The timestamp is to be interpreted identical to the timestamp in the + wl_pointer.axis event. The timestamp value may be the same as a + preceding wl_pointer.axis event. @@ -2360,36 +2360,36 @@ - Discrete step information for scroll and other axes. + Discrete step information for scroll and other axes. - This event carries the axis value of the wl_pointer.axis event in - discrete steps (e.g. mouse wheel clicks). + This event carries the axis value of the wl_pointer.axis event in + discrete steps (e.g. mouse wheel clicks). - This event is deprecated with wl_pointer version 8 - this event is not - sent to clients supporting version 8 or later. + This event is deprecated with wl_pointer version 8 - this event is not + sent to clients supporting version 8 or later. - This event does not occur on its own, it is coupled with a - wl_pointer.axis event that represents this axis value on a - continuous scale. The protocol guarantees that each axis_discrete - event is always followed by exactly one axis event with the same - axis number within the same wl_pointer.frame. Note that the protocol - allows for other events to occur between the axis_discrete and - its coupled axis event, including other axis_discrete or axis - events. A wl_pointer.frame must not contain more than one axis_discrete - event per axis type. + This event does not occur on its own, it is coupled with a + wl_pointer.axis event that represents this axis value on a + continuous scale. The protocol guarantees that each axis_discrete + event is always followed by exactly one axis event with the same + axis number within the same wl_pointer.frame. Note that the protocol + allows for other events to occur between the axis_discrete and + its coupled axis event, including other axis_discrete or axis + events. A wl_pointer.frame must not contain more than one axis_discrete + event per axis type. - This event is optional; continuous scrolling devices - like two-finger scrolling on touchpads do not have discrete - steps and do not generate this event. + This event is optional; continuous scrolling devices + like two-finger scrolling on touchpads do not have discrete + steps and do not generate this event. - The discrete value carries the directional information. e.g. a value - of -2 is two steps towards the negative direction of this axis. + The discrete value carries the directional information. e.g. a value + of -2 is two steps towards the negative direction of this axis. - The axis number is identical to the axis number in the associated - axis event. + The axis number is identical to the axis number in the associated + axis event. - The order of wl_pointer.axis_discrete and wl_pointer.axis_source is - not guaranteed. + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. @@ -2397,27 +2397,27 @@ - Discrete high-resolution scroll information. + Discrete high-resolution scroll information. - This event carries high-resolution wheel scroll information, - with each multiple of 120 representing one logical scroll step - (a wheel detent). For example, an axis_value120 of 30 is one quarter of - a logical scroll step in the positive direction, a value120 of - -240 are two logical scroll steps in the negative direction within the - same hardware event. - Clients that rely on discrete scrolling should accumulate the - value120 to multiples of 120 before processing the event. + This event carries high-resolution wheel scroll information, + with each multiple of 120 representing one logical scroll step + (a wheel detent). For example, an axis_value120 of 30 is one quarter of + a logical scroll step in the positive direction, a value120 of + -240 are two logical scroll steps in the negative direction within the + same hardware event. + Clients that rely on discrete scrolling should accumulate the + value120 to multiples of 120 before processing the event. - The value120 must not be zero. + The value120 must not be zero. - This event replaces the wl_pointer.axis_discrete event in clients - supporting wl_pointer version 8 or later. + This event replaces the wl_pointer.axis_discrete event in clients + supporting wl_pointer version 8 or later. - Where a wl_pointer.axis_source event occurs in the same - wl_pointer.frame, the axis source applies to this event. + Where a wl_pointer.axis_source event occurs in the same + wl_pointer.frame, the axis source applies to this event. - The order of wl_pointer.axis_value120 and wl_pointer.axis_source is - not guaranteed. + The order of wl_pointer.axis_value120 and wl_pointer.axis_source is + not guaranteed. @@ -2427,56 +2427,56 @@ - This specifies the direction of the physical motion that caused a - wl_pointer.axis event, relative to the wl_pointer.axis direction. + This specifies the direction of the physical motion that caused a + wl_pointer.axis event, relative to the wl_pointer.axis direction. + summary="physical motion matches axis direction"/> + summary="physical motion is the inverse of the axis direction"/> - Relative directional information of the entity causing the axis - motion. + Relative directional information of the entity causing the axis + motion. - For a wl_pointer.axis event, the wl_pointer.axis_relative_direction - event specifies the movement direction of the entity causing the - wl_pointer.axis event. For example: - - if a user's fingers on a touchpad move down and this - causes a wl_pointer.axis vertical_scroll down event, the physical - direction is 'identical' - - if a user's fingers on a touchpad move down and this causes a - wl_pointer.axis vertical_scroll up scroll up event ('natural - scrolling'), the physical direction is 'inverted'. + For a wl_pointer.axis event, the wl_pointer.axis_relative_direction + event specifies the movement direction of the entity causing the + wl_pointer.axis event. For example: + - if a user's fingers on a touchpad move down and this + causes a wl_pointer.axis vertical_scroll down event, the physical + direction is 'identical' + - if a user's fingers on a touchpad move down and this causes a + wl_pointer.axis vertical_scroll up scroll up event ('natural + scrolling'), the physical direction is 'inverted'. - A client may use this information to adjust scroll motion of - components. Specifically, enabling natural scrolling causes the - content to change direction compared to traditional scrolling. - Some widgets like volume control sliders should usually match the - physical direction regardless of whether natural scrolling is - active. This event enables clients to match the scroll direction of - a widget to the physical direction. + A client may use this information to adjust scroll motion of + components. Specifically, enabling natural scrolling causes the + content to change direction compared to traditional scrolling. + Some widgets like volume control sliders should usually match the + physical direction regardless of whether natural scrolling is + active. This event enables clients to match the scroll direction of + a widget to the physical direction. - This event does not occur on its own, it is coupled with a - wl_pointer.axis event that represents this axis value. - The protocol guarantees that each axis_relative_direction event is - always followed by exactly one axis event with the same - axis number within the same wl_pointer.frame. Note that the protocol - allows for other events to occur between the axis_relative_direction - and its coupled axis event. + This event does not occur on its own, it is coupled with a + wl_pointer.axis event that represents this axis value. + The protocol guarantees that each axis_relative_direction event is + always followed by exactly one axis event with the same + axis number within the same wl_pointer.frame. Note that the protocol + allows for other events to occur between the axis_relative_direction + and its coupled axis event. - The axis number is identical to the axis number in the associated - axis event. + The axis number is identical to the axis number in the associated + axis event. - The order of wl_pointer.axis_relative_direction, - wl_pointer.axis_discrete and wl_pointer.axis_source is not - guaranteed. + The order of wl_pointer.axis_relative_direction, + wl_pointer.axis_discrete and wl_pointer.axis_source is not + guaranteed. + summary="physical direction relative to axis motion"/> @@ -2498,23 +2498,23 @@ - This specifies the format of the keymap provided to the - client with the wl_keyboard.keymap event. + This specifies the format of the keymap provided to the + client with the wl_keyboard.keymap event. + summary="no keymap; client must understand how to interpret the raw keycode"/> + summary="libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode"/> - This event provides a file descriptor to the client which can be - memory-mapped in read-only mode to provide a keyboard mapping - description. + This event provides a file descriptor to the client which can be + memory-mapped in read-only mode to provide a keyboard mapping + description. - From version 7 onwards, the fd must be mapped with MAP_PRIVATE by - the recipient, as MAP_SHARED may fail. + From version 7 onwards, the fd must be mapped with MAP_PRIVATE by + the recipient, as MAP_SHARED may fail. @@ -2523,19 +2523,19 @@ - Notification that this seat's keyboard focus is on a certain - surface. + Notification that this seat's keyboard focus is on a certain + surface. - The compositor must send the wl_keyboard.modifiers event after this - event. + The compositor must send the wl_keyboard.modifiers event after this + event. - In the wl_keyboard logical state, this event sets the active surface to - the surface argument and the keys currently logically down to the keys - in the keys argument. The compositor must not send this event if the - wl_keyboard already had an active surface immediately before this event. + In the wl_keyboard logical state, this event sets the active surface to + the surface argument and the keys currently logically down to the keys + in the keys argument. The compositor must not send this event if the + wl_keyboard already had an active surface immediately before this event. - Clients should not use the list of pressed keys to emulate key-press - events. The order of keys in the list is unspecified. + Clients should not use the list of pressed keys to emulate key-press + events. The order of keys in the list is unspecified. @@ -2544,16 +2544,16 @@ - Notification that this seat's keyboard focus is no longer on - a certain surface. + Notification that this seat's keyboard focus is no longer on + a certain surface. - The leave notification is sent before the enter notification - for the new focus. + The leave notification is sent before the enter notification + for the new focus. - In the wl_keyboard logical state, this event resets all values to their - defaults. The compositor must not send this event if the active surface - of the wl_keyboard was not equal to the surface argument immediately - before this event. + In the wl_keyboard logical state, this event resets all values to their + defaults. The compositor must not send this event if the active surface + of the wl_keyboard was not equal to the surface argument immediately + before this event. @@ -2561,15 +2561,15 @@ - Describes the physical state of a key that produced the key event. + Describes the physical state of a key that produced the key event. - Since version 10, the key can be in a "repeated" pseudo-state which - means the same as "pressed", but is used to signal repetition in the - key event. + Since version 10, the key can be in a "repeated" pseudo-state which + means the same as "pressed", but is used to signal repetition in the + key event. - The key may only enter the repeated state after entering the pressed - state and before entering the released state. This event may be - generated multiple times while the key is down. + The key may only enter the repeated state after entering the pressed + state and before entering the released state. This event may be + generated multiple times while the key is down. @@ -2578,29 +2578,29 @@ - A key was pressed or released. - The time argument is a timestamp with millisecond - granularity, with an undefined base. + A key was pressed or released. + The time argument is a timestamp with millisecond + granularity, with an undefined base. - The key is a platform-specific key code that can be interpreted - by feeding it to the keyboard mapping (see the keymap event). + The key is a platform-specific key code that can be interpreted + by feeding it to the keyboard mapping (see the keymap event). - If this event produces a change in modifiers, then the resulting - wl_keyboard.modifiers event must be sent after this event. + If this event produces a change in modifiers, then the resulting + wl_keyboard.modifiers event must be sent after this event. - In the wl_keyboard logical state, this event adds the key to the keys - currently logically down (if the state argument is pressed) or removes - the key from the keys currently logically down (if the state argument is - released). The compositor must not send this event if the wl_keyboard - did not have an active surface immediately before this event. The - compositor must not send this event if state is pressed (resp. released) - and the key was already logically down (resp. was not logically down) - immediately before this event. + In the wl_keyboard logical state, this event adds the key to the keys + currently logically down (if the state argument is pressed) or removes + the key from the keys currently logically down (if the state argument is + released). The compositor must not send this event if the wl_keyboard + did not have an active surface immediately before this event. The + compositor must not send this event if state is pressed (resp. released) + and the key was already logically down (resp. was not logically down) + immediately before this event. - Since version 10, compositors may send key events with the "repeated" - key state when a wl_keyboard.repeat_info event with a rate argument of - 0 has been received. This allows the compositor to take over the - responsibility of key repetition. + Since version 10, compositors may send key events with the "repeated" + key state when a wl_keyboard.repeat_info event with a rate argument of + 0 has been received. This allows the compositor to take over the + responsibility of key repetition. @@ -2610,19 +2610,19 @@ - Notifies clients that the modifier and/or group state has - changed, and it should update its local state. + Notifies clients that the modifier and/or group state has + changed, and it should update its local state. - The compositor may send this event without a surface of the client - having keyboard focus, for example to tie modifier information to - pointer focus instead. If a modifier event with pressed modifiers is sent - without a prior enter event, the client can assume the modifier state is - valid until it receives the next wl_keyboard.modifiers event. In order to - reset the modifier state again, the compositor can send a - wl_keyboard.modifiers event with no pressed modifiers. + The compositor may send this event without a surface of the client + having keyboard focus, for example to tie modifier information to + pointer focus instead. If a modifier event with pressed modifiers is sent + without a prior enter event, the client can assume the modifier state is + valid until it receives the next wl_keyboard.modifiers event. In order to + reset the modifier state again, the compositor can send a + wl_keyboard.modifiers event with no pressed modifiers. - In the wl_keyboard logical state, this event updates the modifiers and - group. + In the wl_keyboard logical state, this event updates the modifiers and + group. @@ -2641,23 +2641,23 @@ - Informs the client about the keyboard's repeat rate and delay. + Informs the client about the keyboard's repeat rate and delay. - This event is sent as soon as the wl_keyboard object has been created, - and is guaranteed to be received by the client before any key press - event. + This event is sent as soon as the wl_keyboard object has been created, + and is guaranteed to be received by the client before any key press + event. - Negative values for either rate or delay are illegal. A rate of zero - will disable any repeating (regardless of the value of delay). + Negative values for either rate or delay are illegal. A rate of zero + will disable any repeating (regardless of the value of delay). - This event can be sent later on as well with a new value if necessary, - so clients should continue listening for the event past the creation - of wl_keyboard. + This event can be sent later on as well with a new value if necessary, + so clients should continue listening for the event past the creation + of wl_keyboard. + summary="the rate of repeating keys in characters per second"/> + summary="delay in milliseconds since key down until repeating starts"/> @@ -2675,10 +2675,10 @@ - A new touch point has appeared on the surface. This touch point is - assigned a unique ID. Future events from this touch point reference - this ID. The ID ceases to be valid after a touch up event and may be - reused in the future. + A new touch point has appeared on the surface. This touch point is + assigned a unique ID. Future events from this touch point reference + this ID. The ID ceases to be valid after a touch up event and may be + reused in the future. @@ -2690,9 +2690,9 @@ - The touch point has disappeared. No further events will be sent for - this touch point and the touch point's ID is released and may be - reused in a future touch down event. + The touch point has disappeared. No further events will be sent for + this touch point and the touch point's ID is released and may be + reused in a future touch down event. @@ -2701,7 +2701,7 @@ - A touch point has changed coordinates. + A touch point has changed coordinates. @@ -2711,27 +2711,27 @@ - Indicates the end of a set of events that logically belong together. - A client is expected to accumulate the data in all events within the - frame before proceeding. + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. - A wl_touch.frame terminates at least one event but otherwise no - guarantee is provided about the set of events within a frame. A client - must assume that any state not updated in a frame is unchanged from the - previously known state. + A wl_touch.frame terminates at least one event but otherwise no + guarantee is provided about the set of events within a frame. A client + must assume that any state not updated in a frame is unchanged from the + previously known state. - Sent if the compositor decides the touch stream is a global - gesture. No further events are sent to the clients from that - particular gesture. Touch cancellation applies to all touch points - currently active on this client's surface. The client is - responsible for finalizing the touch points, future touch points on - this surface may reuse the touch point ID. + Sent if the compositor decides the touch stream is a global + gesture. No further events are sent to the clients from that + particular gesture. Touch cancellation applies to all touch points + currently active on this client's surface. The client is + responsible for finalizing the touch points, future touch points on + this surface may reuse the touch point ID. - No frame event is required after the cancel event. + No frame event is required after the cancel event. @@ -2745,31 +2745,31 @@ - Sent when a touchpoint has changed its shape. + Sent when a touchpoint has changed its shape. - This event does not occur on its own. It is sent before a - wl_touch.frame event and carries the new shape information for - any previously reported, or new touch points of that frame. + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. - Other events describing the touch point such as wl_touch.down, - wl_touch.motion or wl_touch.orientation may be sent within the - same wl_touch.frame. A client should treat these events as a single - logical touch point update. The order of wl_touch.shape, - wl_touch.orientation and wl_touch.motion is not guaranteed. - A wl_touch.down event is guaranteed to occur before the first - wl_touch.shape event for this touch ID but both events may occur within - the same wl_touch.frame. + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.orientation may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.shape event for this touch ID but both events may occur within + the same wl_touch.frame. - A touchpoint shape is approximated by an ellipse through the major and - minor axis length. The major axis length describes the longer diameter - of the ellipse, while the minor axis length describes the shorter - diameter. Major and minor are orthogonal and both are specified in - surface-local coordinates. The center of the ellipse is always at the - touchpoint location as reported by wl_touch.down or wl_touch.move. + A touchpoint shape is approximated by an ellipse through the major and + minor axis length. The major axis length describes the longer diameter + of the ellipse, while the minor axis length describes the shorter + diameter. Major and minor are orthogonal and both are specified in + surface-local coordinates. The center of the ellipse is always at the + touchpoint location as reported by wl_touch.down or wl_touch.move. - This event is only sent by the compositor if the touch device supports - shape reports. The client has to make reasonable assumptions about the - shape if it did not receive this event. + This event is only sent by the compositor if the touch device supports + shape reports. The client has to make reasonable assumptions about the + shape if it did not receive this event. @@ -2778,29 +2778,29 @@ - Sent when a touchpoint has changed its orientation. + Sent when a touchpoint has changed its orientation. - This event does not occur on its own. It is sent before a - wl_touch.frame event and carries the new shape information for - any previously reported, or new touch points of that frame. + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. - Other events describing the touch point such as wl_touch.down, - wl_touch.motion or wl_touch.shape may be sent within the - same wl_touch.frame. A client should treat these events as a single - logical touch point update. The order of wl_touch.shape, - wl_touch.orientation and wl_touch.motion is not guaranteed. - A wl_touch.down event is guaranteed to occur before the first - wl_touch.orientation event for this touch ID but both events may occur - within the same wl_touch.frame. + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.shape may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.orientation event for this touch ID but both events may occur + within the same wl_touch.frame. - The orientation describes the clockwise angle of a touchpoint's major - axis to the positive surface y-axis and is normalized to the -180 to - +180 degree range. The granularity of orientation depends on the touch - device, some devices only support binary rotation values between 0 and - 90 degrees. + The orientation describes the clockwise angle of a touchpoint's major + axis to the positive surface y-axis and is normalized to the -180 to + +180 degree range. The granularity of orientation depends on the touch + device, some devices only support binary rotation values between 0 and + 90 degrees. - This event is only sent by the compositor if the touch device supports - orientation reports. + This event is only sent by the compositor if the touch device supports + orientation reports. @@ -2819,8 +2819,8 @@ - This enumeration describes how the physical - pixels on an output are laid out. + This enumeration describes how the physical + pixels on an output are laid out. @@ -2832,16 +2832,16 @@ - This describes transformations that clients and compositors apply to - buffer contents. + This describes transformations that clients and compositors apply to + buffer contents. - The flipped values correspond to an initial flip around a - vertical axis followed by rotation. + The flipped values correspond to an initial flip around a + vertical axis followed by rotation. - The purpose is mainly to allow clients to render accordingly and - tell the compositor, so that for fullscreen surfaces, the - compositor will still be able to scan out directly from client - surfaces. + The purpose is mainly to allow clients to render accordingly and + tell the compositor, so that for fullscreen surfaces, the + compositor will still be able to scan out directly from client + surfaces. @@ -2855,91 +2855,91 @@ - The geometry event describes geometric properties of the output. - The event is sent when binding to the output object and whenever - any of the properties change. + The geometry event describes geometric properties of the output. + The event is sent when binding to the output object and whenever + any of the properties change. - The physical size can be set to zero if it doesn't make sense for this - output (e.g. for projectors or virtual outputs). + The physical size can be set to zero if it doesn't make sense for this + output (e.g. for projectors or virtual outputs). - The geometry event will be followed by a done event (starting from - version 2). + The geometry event will be followed by a done event (starting from + version 2). - Clients should use wl_surface.preferred_buffer_transform instead of the - transform advertised by this event to find the preferred buffer - transform to use for a surface. + Clients should use wl_surface.preferred_buffer_transform instead of the + transform advertised by this event to find the preferred buffer + transform to use for a surface. - Note: wl_output only advertises partial information about the output - position and identification. Some compositors, for instance those not - implementing a desktop-style output layout or those exposing virtual - outputs, might fake this information. Instead of using x and y, clients - should use xdg_output.logical_position. Instead of using make and model, - clients should use name and description. + Note: wl_output only advertises partial information about the output + position and identification. Some compositors, for instance those not + implementing a desktop-style output layout or those exposing virtual + outputs, might fake this information. Instead of using x and y, clients + should use xdg_output.logical_position. Instead of using make and model, + clients should use name and description. + summary="x position within the global compositor space"/> + summary="y position within the global compositor space"/> + summary="width in millimeters of the output"/> + summary="height in millimeters of the output"/> + summary="subpixel orientation of the output"/> + summary="textual description of the manufacturer"/> + summary="textual description of the model"/> + summary="additional transformation applied to buffer contents during presentation"/> - These flags describe properties of an output mode. - They are used in the flags bitfield of the mode event. + These flags describe properties of an output mode. + They are used in the flags bitfield of the mode event. + summary="indicates this is the current mode"/> + summary="indicates this is the preferred mode"/> - The mode event describes an available mode for the output. + The mode event describes an available mode for the output. - The event is sent when binding to the output object and there - will always be one mode, the current mode. The event is sent - again if an output changes mode, for the mode that is now - current. In other words, the current mode is always the last - mode that was received with the current flag set. + The event is sent when binding to the output object and there + will always be one mode, the current mode. The event is sent + again if an output changes mode, for the mode that is now + current. In other words, the current mode is always the last + mode that was received with the current flag set. - Non-current modes are deprecated. A compositor can decide to only - advertise the current mode and never send other modes. Clients - should not rely on non-current modes. + Non-current modes are deprecated. A compositor can decide to only + advertise the current mode and never send other modes. Clients + should not rely on non-current modes. - The size of a mode is given in physical hardware units of - the output device. This is not necessarily the same as - the output size in the global compositor space. For instance, - the output may be scaled, as described in wl_output.scale, - or transformed, as described in wl_output.transform. Clients - willing to retrieve the output size in the global compositor - space should use xdg_output.logical_size instead. + The size of a mode is given in physical hardware units of + the output device. This is not necessarily the same as + the output size in the global compositor space. For instance, + the output may be scaled, as described in wl_output.scale, + or transformed, as described in wl_output.transform. Clients + willing to retrieve the output size in the global compositor + space should use xdg_output.logical_size instead. - The vertical refresh rate can be set to zero if it doesn't make - sense for this output (e.g. for virtual outputs). + The vertical refresh rate can be set to zero if it doesn't make + sense for this output (e.g. for virtual outputs). - The mode event will be followed by a done event (starting from - version 2). + The mode event will be followed by a done event (starting from + version 2). - Clients should not use the refresh rate to schedule frames. Instead, - they should use the wl_surface.frame event or the presentation-time - protocol. + Clients should not use the refresh rate to schedule frames. Instead, + they should use the wl_surface.frame event or the presentation-time + protocol. - Note: this information is not always meaningful for all outputs. Some - compositors, such as those exposing virtual outputs, might fake the - refresh rate or the size. + Note: this information is not always meaningful for all outputs. Some + compositors, such as those exposing virtual outputs, might fake the + refresh rate or the size. @@ -2951,34 +2951,34 @@ - This event is sent after all other properties have been - sent after binding to the output object and after any - other property changes done after that. This allows - changes to the output properties to be seen as - atomic, even if they happen via multiple events. + This event is sent after all other properties have been + sent after binding to the output object and after any + other property changes done after that. This allows + changes to the output properties to be seen as + atomic, even if they happen via multiple events. - This event contains scaling geometry information - that is not in the geometry event. It may be sent after - binding the output object or if the output scale changes - later. The compositor will emit a non-zero, positive - value for scale. If it is not sent, the client should - assume a scale of 1. + This event contains scaling geometry information + that is not in the geometry event. It may be sent after + binding the output object or if the output scale changes + later. The compositor will emit a non-zero, positive + value for scale. If it is not sent, the client should + assume a scale of 1. - A scale larger than 1 means that the compositor will - automatically scale surface buffers by this amount - when rendering. This is used for very high resolution - displays where applications rendering at the native - resolution would be too small to be legible. + A scale larger than 1 means that the compositor will + automatically scale surface buffers by this amount + when rendering. This is used for very high resolution + displays where applications rendering at the native + resolution would be too small to be legible. - Clients should use wl_surface.preferred_buffer_scale - instead of this event to find the preferred buffer - scale to use for a surface. + Clients should use wl_surface.preferred_buffer_scale + instead of this event to find the preferred buffer + scale to use for a surface. - The scale event will be followed by a done event. + The scale event will be followed by a done event. @@ -2987,8 +2987,8 @@ - Using this request a client can tell the server that it is not going to - use the output object anymore. + Using this request a client can tell the server that it is not going to + use the output object anymore. @@ -2996,54 +2996,54 @@ - Many compositors will assign user-friendly names to their outputs, show - them to the user, allow the user to refer to an output, etc. The client - may wish to know this name as well to offer the user similar behaviors. + Many compositors will assign user-friendly names to their outputs, show + them to the user, allow the user to refer to an output, etc. The client + may wish to know this name as well to offer the user similar behaviors. - The name is a UTF-8 string with no convention defined for its contents. - Each name is unique among all wl_output globals. The name is only - guaranteed to be unique for the compositor instance. + The name is a UTF-8 string with no convention defined for its contents. + Each name is unique among all wl_output globals. The name is only + guaranteed to be unique for the compositor instance. - The same output name is used for all clients for a given wl_output - global. Thus, the name can be shared across processes to refer to a - specific wl_output global. + The same output name is used for all clients for a given wl_output + global. Thus, the name can be shared across processes to refer to a + specific wl_output global. - The name is not guaranteed to be persistent across sessions, thus cannot - be used to reliably identify an output in e.g. configuration files. + The name is not guaranteed to be persistent across sessions, thus cannot + be used to reliably identify an output in e.g. configuration files. - Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do - not assume that the name is a reflection of an underlying DRM connector, - X11 connection, etc. + Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do + not assume that the name is a reflection of an underlying DRM connector, + X11 connection, etc. - The name event is sent after binding the output object. This event is - only sent once per output object, and the name does not change over the - lifetime of the wl_output global. + The name event is sent after binding the output object. This event is + only sent once per output object, and the name does not change over the + lifetime of the wl_output global. - Compositors may re-use the same output name if the wl_output global is - destroyed and re-created later. Compositors should avoid re-using the - same name if possible. + Compositors may re-use the same output name if the wl_output global is + destroyed and re-created later. Compositors should avoid re-using the + same name if possible. - The name event will be followed by a done event. + The name event will be followed by a done event. - Many compositors can produce human-readable descriptions of their - outputs. The client may wish to know this description as well, e.g. for - output selection purposes. + Many compositors can produce human-readable descriptions of their + outputs. The client may wish to know this description as well, e.g. for + output selection purposes. - The description is a UTF-8 string with no convention defined for its - contents. The description is not guaranteed to be unique among all - wl_output globals. Examples might include 'Foocorp 11" Display' or - 'Virtual X11 output via :1'. + The description is a UTF-8 string with no convention defined for its + contents. The description is not guaranteed to be unique among all + wl_output globals. Examples might include 'Foocorp 11" Display' or + 'Virtual X11 output via :1'. - The description event is sent after binding the output object and - whenever the description changes. The description is optional, and may - not be sent at all. + The description event is sent after binding the output object and + whenever the description changes. The description is optional, and may + not be sent at all. - The description event will be followed by a done event. + The description event will be followed by a done event. @@ -3059,13 +3059,13 @@ - Destroy the region. This will invalidate the object ID. + Destroy the region. This will invalidate the object ID. - Add the specified rectangle to the region. + Add the specified rectangle to the region. @@ -3075,7 +3075,7 @@ - Subtract the specified rectangle from the region. + Subtract the specified rectangle from the region. @@ -3109,47 +3109,47 @@ - Informs the server that the client will not be using this - protocol object anymore. This does not affect any other - objects, wl_subsurface objects included. + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other + objects, wl_subsurface objects included. + summary="the to-be sub-surface is invalid"/> + summary="the to-be sub-surface parent is invalid"/> - Create a sub-surface interface for the given surface, and - associate it with the given parent surface. This turns a - plain wl_surface into a sub-surface. + Create a sub-surface interface for the given surface, and + associate it with the given parent surface. This turns a + plain wl_surface into a sub-surface. - The to-be sub-surface must not already have another role, and it - must not have an existing wl_subsurface object. Otherwise the - bad_surface protocol error is raised. + The to-be sub-surface must not already have another role, and it + must not have an existing wl_subsurface object. Otherwise the + bad_surface protocol error is raised. - Adding sub-surfaces to a parent is a double-buffered operation on the - parent (see wl_surface.commit). The effect of adding a sub-surface - becomes visible on the next time the state of the parent surface is - applied. + Adding sub-surfaces to a parent is a double-buffered operation on the + parent (see wl_surface.commit). The effect of adding a sub-surface + becomes visible on the next time the state of the parent surface is + applied. - The parent surface must not be one of the child surface's descendants, - and the parent must be different from the child surface, otherwise the - bad_parent protocol error is raised. + The parent surface must not be one of the child surface's descendants, + and the parent must be different from the child surface, otherwise the + bad_parent protocol error is raised. - This request modifies the behaviour of wl_surface.commit request on - the sub-surface, see the documentation on wl_subsurface interface. + This request modifies the behaviour of wl_surface.commit request on + the sub-surface, see the documentation on wl_subsurface interface. + summary="the new sub-surface object ID"/> + summary="the surface to be turned into a sub-surface"/> + summary="the parent surface"/> @@ -3206,32 +3206,32 @@ - The sub-surface interface is removed from the wl_surface object - that was turned into a sub-surface with a - wl_subcompositor.get_subsurface request. The wl_surface's association - to the parent is deleted. The wl_surface is unmapped immediately. + The sub-surface interface is removed from the wl_surface object + that was turned into a sub-surface with a + wl_subcompositor.get_subsurface request. The wl_surface's association + to the parent is deleted. The wl_surface is unmapped immediately. + summary="wl_surface is not a sibling or the parent"/> - This sets the position of the sub-surface, relative to the parent - surface. + This sets the position of the sub-surface, relative to the parent + surface. - The sub-surface will be moved so that its origin (top left - corner pixel) will be at the location x, y of the parent surface - coordinate system. The coordinates are not restricted to the parent - surface area. Negative values are allowed. + The sub-surface will be moved so that its origin (top left + corner pixel) will be at the location x, y of the parent surface + coordinate system. The coordinates are not restricted to the parent + surface area. Negative values are allowed. - The initial position is 0, 0. + The initial position is 0, 0. - Position is double-buffered state on the parent surface, see - wl_subsurface and wl_surface.commit for more information. + Position is double-buffered state on the parent surface, see + wl_subsurface and wl_surface.commit for more information. @@ -3239,47 +3239,47 @@ - This sub-surface is taken from the stack, and put back just - above the reference surface, changing the z-order of the sub-surfaces. - The reference surface must be one of the sibling surfaces, or the - parent surface. Using any other surface, including this sub-surface, - will cause a protocol error. + This sub-surface is taken from the stack, and put back just + above the reference surface, changing the z-order of the sub-surfaces. + The reference surface must be one of the sibling surfaces, or the + parent surface. Using any other surface, including this sub-surface, + will cause a protocol error. - A new sub-surface is initially added as the top-most in the stack - of its siblings and parent. + A new sub-surface is initially added as the top-most in the stack + of its siblings and parent. - Z-order is double-buffered state on the parent surface, see - wl_subsurface and wl_surface.commit for more information. + Z-order is double-buffered state on the parent surface, see + wl_subsurface and wl_surface.commit for more information. + summary="the reference surface"/> - The sub-surface is placed just below the reference surface. + The sub-surface is placed just below the reference surface. - See wl_subsurface.place_above. + See wl_subsurface.place_above. + summary="the reference surface"/> - Change the commit behaviour of the sub-surface to synchronized - mode. + Change the commit behaviour of the sub-surface to synchronized + mode. - See wl_subsurface and wl_surface.commit for more information. + See wl_subsurface and wl_surface.commit for more information. - Change the commit behaviour of the sub-surface to desynchronized - mode. + Change the commit behaviour of the sub-surface to desynchronized + mode. - See wl_subsurface and wl_surface.commit for more information. + See wl_subsurface and wl_surface.commit for more information. @@ -3296,18 +3296,18 @@ - This request destroys a wl_registry object. + This request destroys a wl_registry object. - The client should no longer use the wl_registry after making this - request. + The client should no longer use the wl_registry after making this + request. - The compositor will emit a wl_display.delete_id event with the object ID - of the registry and will no longer emit any events on the registry. The - client should re-use the object ID once it receives the - wl_display.delete_id event. + The compositor will emit a wl_display.delete_id event with the object ID + of the registry and will no longer emit any events on the registry. The + client should re-use the object ID once it receives the + wl_display.delete_id event. + summary="the registry to destroy"/> From a7ee144aec9b1b88536263047bf3e2b45d692f1f Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 23 Jan 2026 15:07:46 +0100 Subject: [PATCH 1116/1152] add .git-blame-ignore-revs file This can be used with git config blame.ignoreRevsFile .git-blame-ignore-revs Signed-off-by: Julian Orth --- .git-blame-ignore-revs | 4 ++++ git-blame-ignore-revs | 1 + 2 files changed, 5 insertions(+) create mode 100644 .git-blame-ignore-revs create mode 120000 git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..8110e58b --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# Use the following command to ignore the following commits in git blame: +# git config blame.ignoreRevsFile .git-blame-ignore-revs + +e5a2d26755e9f54d2d501b9ae30e49bc22e00a07 # protocol: reindent wayland.xml diff --git a/git-blame-ignore-revs b/git-blame-ignore-revs new file mode 120000 index 00000000..c17c5dd1 --- /dev/null +++ b/git-blame-ignore-revs @@ -0,0 +1 @@ +.git-blame-ignore-revs \ No newline at end of file From dbf45d11a324fffdc1122a303c691898f942c508 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 2 Feb 2026 14:00:25 +0100 Subject: [PATCH 1117/1152] fix .git-blame-ignore-revs revision The commit hash was changed during merge. Signed-off-by: Julian Orth --- .git-blame-ignore-revs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8110e58b..311e3e0e 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,4 +1,4 @@ # Use the following command to ignore the following commits in git blame: # git config blame.ignoreRevsFile .git-blame-ignore-revs -e5a2d26755e9f54d2d501b9ae30e49bc22e00a07 # protocol: reindent wayland.xml +77b9eb76369e27142b8be296b5f2eb1ca466272a # protocol: reindent wayland.xml From e12bbe496941e546165055f9520745b7ba4366ce Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 29 Jan 2026 11:57:29 +0200 Subject: [PATCH 1118/1152] doc: make DocBook validation optional It turns out that changes in the building environment, the version of Doxygen being a prime suspect, can break the validation. Invalid DocBook XML does lead to likely broken documentation, but perhaps it is better than failing to build or having to disable documentation completely. CI turns DocBook validation on, because the CI environment is stable and known, and we do want to catch mistakes in hand-written DocBook files. Signed-off-by: Pekka Paalanen --- .gitlab-ci.yml | 2 +- doc/publican/meson.build | 7 ++++++- meson_options.txt | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 39beeaf3..9816859a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -159,7 +159,7 @@ armv7-debian-container_prep: # Core build environment. .build-env: variables: - MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined" + MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined -Ddocbook_validation=true" # See https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/154 ASAN_OPTIONS: "detect_odr_violation=0" before_script: diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 1aa31d3c..a572b0eb 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -94,11 +94,16 @@ foreach src : files([ ) endforeach +skip_validation = '--skip-validation' +if get_option('docbook_validation') + skip_validation = [] +endif + custom_target( 'Wayland-docbook-html', command: [ xmlto, - '--skip-validation', + skip_validation, '--stringparam', 'chunker.output.encoding=UTF-8', '--stringparam', 'chunk.section.depth=0', '--stringparam', 'toc.section.depth=1', diff --git a/meson_options.txt b/meson_options.txt index b8e2ec60..02c2346a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -14,6 +14,10 @@ option('documentation', description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)', type: 'boolean', value: true) +option('docbook_validation', + type: 'boolean', + value: false, + description: 'Validate the intermediate DocBook XML during the documentation build') option('dtd_validation', description: 'Validate the protocol DTD (requires libxml2)', type: 'boolean', From 5818c9361a59a076f68315493336ebe3217e7191 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 30 Jan 2026 21:05:33 +0100 Subject: [PATCH 1119/1152] doc: add docbook -> mdbook conversion tool Signed-off-by: Julian Orth --- docbook-to-mdbook/.gitignore | 1 + docbook-to-mdbook/Cargo.lock | 184 +++++++ docbook-to-mdbook/Cargo.toml | 12 + docbook-to-mdbook/rustfmt.toml | 1 + docbook-to-mdbook/src/main.rs | 935 +++++++++++++++++++++++++++++++++ 5 files changed, 1133 insertions(+) create mode 100644 docbook-to-mdbook/.gitignore create mode 100644 docbook-to-mdbook/Cargo.lock create mode 100644 docbook-to-mdbook/Cargo.toml create mode 100644 docbook-to-mdbook/rustfmt.toml create mode 100644 docbook-to-mdbook/src/main.rs diff --git a/docbook-to-mdbook/.gitignore b/docbook-to-mdbook/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/docbook-to-mdbook/.gitignore @@ -0,0 +1 @@ +/target diff --git a/docbook-to-mdbook/Cargo.lock b/docbook-to-mdbook/Cargo.lock new file mode 100644 index 00000000..507516d9 --- /dev/null +++ b/docbook-to-mdbook/Cargo.lock @@ -0,0 +1,184 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "docbook-to-mdbook" +version = "0.1.0" +dependencies = [ + "anyhow", + "bstr", + "isnt", + "quick-xml", + "regex", + "textwrap", +] + +[[package]] +name = "isnt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1697e6b71679da96d5c41bb9035116141baadbf59a60625fd66cb3c9584e7b0" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" diff --git a/docbook-to-mdbook/Cargo.toml b/docbook-to-mdbook/Cargo.toml new file mode 100644 index 00000000..508f379d --- /dev/null +++ b/docbook-to-mdbook/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "docbook-to-mdbook" +version = "0.1.0" +edition = "2024" + +[dependencies] +quick-xml = "0.39.0" +anyhow = "1.0.100" +bstr = "1.12.1" +textwrap = "0.16.2" +regex = "1.12.2" +isnt = "0.2.0" diff --git a/docbook-to-mdbook/rustfmt.toml b/docbook-to-mdbook/rustfmt.toml new file mode 100644 index 00000000..58b51174 --- /dev/null +++ b/docbook-to-mdbook/rustfmt.toml @@ -0,0 +1 @@ +imports_granularity = "One" diff --git a/docbook-to-mdbook/src/main.rs b/docbook-to-mdbook/src/main.rs new file mode 100644 index 00000000..3ebc5493 --- /dev/null +++ b/docbook-to-mdbook/src/main.rs @@ -0,0 +1,935 @@ +#![expect(clippy::single_char_add_str)] + +use { + anyhow::{Context, bail}, + bstr::ByteSlice, + isnt::std_1::primitive::IsntStrExt, + quick_xml::{ + Reader, + events::{BytesStart, Event}, + }, + regex::Regex, + std::{ + borrow::Cow, + fs::{File, read_dir}, + io::{BufWriter, Write}, + mem, + path::Path, + sync::LazyLock, + }, + textwrap::{Options, WordSeparator, WordSplitter, WrapAlgorithm}, +}; + +const XML_ROOT: &str = "../doc/publican"; +const MD_ROOT: &str = "../doc/book"; + +fn main() -> anyhow::Result<()> { + for file in read_dir(XML_ROOT).context("open publican")? { + let file = file.unwrap(); + let path = file.path(); + let Some(name) = path.file_name() else { + continue; + }; + let name = name.to_str().unwrap(); + if !name.ends_with(".xml") { + continue; + } + match name { + "Architecture.xml" + | "Color.xml" + | "Compositors.xml" + | "Content_Updates.xml" + | "Introduction.xml" + | "Message_XML.xml" + | "Protocol.xml" + | "Foreword.xml" + | "Xwayland.xml" => handle_chapter_file(name) + .with_context(|| format!("handle_chapter_file {}", name))?, + "Book_Info.xml" | "Wayland.xml" | "Author_Group.xml" | "Client.xml" | "Server.xml" => { + continue; + } + _ => bail!("unknown file name {name}"), + } + } + handle_wayland_xml().context("Wayland.xml")?; + Ok(()) +} + +fn handle_wayland_xml() -> anyhow::Result<()> { + let input = Path::new(XML_ROOT).join("Wayland.xml"); + let input = std::fs::read_to_string(input).context("read xml")?; + let mut r = Reader::from_str(&input); + let output = Path::new(MD_ROOT).join("src").join("SUMMARY.md"); + let mut w = BufWriter::new(File::create(output).context("open md")?); + writeln!(w, "# Summary")?; + writeln!(w)?; + writeln!(w, "[Foreword](Foreword.md)")?; + writeln!(w)?; + loop { + let event = r.read_event().context("read event")?; + match event { + Event::Start(c) => match c.name().as_ref() { + b"book" => loop { + let event = r.read_event().context("read event")?; + match event { + Event::Empty(e) if e.name().as_ref() == b"xi:include" => { + let href = e + .try_get_attribute("href") + .context("href")? + .context("href")? + .unescape_value() + .context("href")?; + let name = match &*href { + "Book_Info.xml" => continue, + "Foreword.xml" => continue, + "Introduction.xml" => "Introduction", + "Compositors.xml" => "Types of Compositors", + "Architecture.xml" => "Wayland Architecture", + "Protocol.xml" => "Wayland Protocol and Model of Operation", + "Message_XML.xml" => "Message Definition Language", + "Xwayland.xml" => "X11 Application Support", + "Content_Updates.xml" => "Content Updates", + "Color.xml" => "Color management", + "ProtocolSpec.xml" => continue, + "Client.xml" => continue, + "Server.xml" => continue, + _ => bail!("unexpected link {href}"), + }; + writeln!(w, "- [{name}](./{})", href.replace(".xml", ".md"))?; + } + Event::Text(t) if t.trim().is_empty() => {} + Event::End(e) if e.name().as_ref() == b"book" => break, + _ => bail!("unexpected event {event:?}"), + } + }, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::Decl(_) => {} + Event::DocType(_) => {} + Event::Text(t) if t.trim().is_empty() => {} + Event::Eof => break, + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) +} + +fn handle_chapter_file(name: &str) -> anyhow::Result<()> { + let input = Path::new(XML_ROOT).join(name); + let input = std::fs::read_to_string(input).context("read xml")?; + let mut reader = Reader::from_str(&input); + let output = Path::new(MD_ROOT) + .join("src") + .join(name) + .with_extension("md"); + let mut output = BufWriter::new(File::create(output).context("open md")?); + Handler { + w: &mut output, + r: &mut reader, + text: Default::default(), + need_newline: false, + last_line_has_content: false, + have_indent_1: Default::default(), + indent_1: Default::default(), + indent_2: Default::default(), + } + .handle_chapter_file() +} + +struct Handler<'a, 'b, W> { + w: &'a mut W, + r: &'a mut Reader<&'b [u8]>, + text: String, + need_newline: bool, + last_line_has_content: bool, + have_indent_1: bool, + indent_1: String, + indent_2: String, +} + +#[derive(Copy, Clone, Eq, PartialEq)] +enum TitleType { + Chapter, + Section(usize), + Bold, +} + +enum ListType { + Bullet, + Numbered(usize), + Itemized, +} + +static WHITESPACE: LazyLock = LazyLock::new(|| Regex::new(r#"[\n\t ]+"#).unwrap()); + +impl Handler<'_, '_, W> +where + W: Write, +{ + fn handle_chapter_file(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + match event { + Event::Start(c) => match c.name().as_ref() { + b"preface" | b"chapter" => self.handle_chapter().context("handle_chapter")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::Decl(_) => {} + Event::DocType(_) => {} + Event::Text(t) if t.trim().is_empty() => {} + Event::Eof => break, + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_chapter(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(s) => match s.name().as_ref() { + b"title" => self + .handle_title(TitleType::Chapter) + .context("handle_title")?, + b"literallayout" | b"para" => self.handle_para(false).context("handle_para")?, + b"section" => self.handle_section(0).context("handle_section")?, + _ => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::Empty(s) if s.name().as_ref() == b"xi:include" => {} + Event::End(e) if e.name().as_ref() == b"chapter" => break, + Event::End(e) if e.name().as_ref() == b"preface" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_title(&mut self, ty: TitleType) -> anyhow::Result<()> { + match ty { + TitleType::Chapter => self.text.push_str("# "), + TitleType::Section(depth) => { + self.text.push_str("##"); + for _ in 0..depth { + self.text.push_str("#"); + } + self.text.push_str(" "); + } + TitleType::Bold => self.text.push_str("**"), + } + let mut first = true; + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Text(v) => { + if first { + first = false; + } else { + self.text.push_str(" "); + } + self.text.push_str(v.decode().unwrap().trim()); + } + Event::End(v) if &*v == b"title" => break, + _ => bail!("unexpected event {event:?}"), + } + } + match ty { + TitleType::Chapter => {} + TitleType::Section(_) => {} + TitleType::Bold => self.text.push_str("**"), + } + let text = mem::take(&mut self.text); + self.write_line(&text)?; + self.text = text; + self.text.clear(); + self.need_newline = true; + Ok(()) + } + + fn handle_section(&mut self, depth: usize) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(s) => match s.name().as_ref() { + b"section" => self.handle_section(depth + 1).context("handle_section")?, + b"title" => self + .handle_title(TitleType::Section(depth)) + .context("handle_title")?, + b"synopsis" => self.handle_para(true).context("handle_synopsis")?, + b"para" => self.handle_para(false).context("handle_para")?, + b"orderedlist" => self.handle_orderedlist().context("handle_orderedlist")?, + b"itemizedlist" => self.handle_itemizedlist().context("handle_itemizedlist")?, + b"figure" => self.handle_figure().context("handle_figure")?, + b"variablelist" => self.handle_variablelist().context("handle_variablelist")?, + b"mediaobject" | b"mediaobjectco" => { + self.handle_mediaobject().context("handle_mediaobject")? + } + _ => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"section" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_xref(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { + let url = e + .try_get_attribute("linkend") + .context("linkend")? + .context("linkend")? + .unescape_value() + .context("linkend")?; + let name_buf; + let url_buf; + let (name, url) = if let Some(v) = url.strip_prefix("sect-") + && let Some((sect, v)) = v.split_once("-") + { + match sect { + "Protocol" => match v { + "Wire-Format" => ("Wire Format", "#wire-format"), + "data-sharing-devices" => ("Data devices", "#data-devices"), + _ => bail!("unhandled protocol link {url}"), + }, + "MessageXML" => match v { + "tag-interface" => ("interface", "#interface"), + "tag-arg" => ("arg", "#arg"), + _ => bail!("unhandled message-xml link {url}"), + }, + _ => bail!("unhandled section {url}"), + } + } else if let Some(v) = url.strip_prefix("chap-") { + match v { + "Protocol" => ("Wayland Protocol and Model of Operation", "Protocol.md"), + _ => bail!("unhandled chap {url}"), + } + } else if let Some(v) = url.strip_prefix("protocol-spec-") { + if let Some((interface, v)) = v.split_once("-") + && let Some((ty, message)) = v.split_once("-") + { + name_buf = format!("{interface}.{message}"); + url_buf = + format!("https://wayland.app/protocols/wayland#{interface}:{ty}:{message}"); + } else { + name_buf = v.to_string(); + url_buf = format!("https://wayland.app/protocols/wayland#{v}"); + } + (&*name_buf, &*url_buf) + } else { + bail!("unknown link format {url}"); + }; + self.text.push_str("["); + self.text.push_str(name); + self.text.push_str("]"); + self.text.push_str("("); + self.text.push_str(url); + self.text.push_str(")"); + Ok(()) + } + + fn handle_filename(&mut self) -> anyhow::Result<()> { + let mut text = String::new(); + loop { + let event = self.r.read_event().context("read event")?; + match event { + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + text.push_str(&s); + } + Event::End(v) if &*v == b"filename" => break, + _ => bail!("unexpected event {event:?}"), + } + } + self.text.push_str("["); + self.text.push_str(text.trim()); + self.text.push_str("]"); + self.text + .push_str("(https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/"); + self.text.push_str(&text); + self.text.push_str(")"); + Ok(()) + } + + fn handle_link(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { + let mut text = String::new(); + loop { + let event = self.r.read_event().context("read event")?; + match event { + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + text.push_str(&s); + } + Event::End(v) if &*v == b"link" => break, + _ => bail!("unexpected event {event:?}"), + } + } + let url = e + .try_get_attribute("linkend") + .context("linkend")? + .context("linkend")? + .unescape_value() + .context("linkend")?; + let buf; + let url = if let Some(v) = url.strip_prefix("sect-") + && let Some((sect, v)) = v.split_once("-") + { + match sect { + "Compositors" => match v { + "System-Compositor" => "#system-compositor", + "Session-Compositor" => "#session-compositor", + _ => bail!("unhandled compositors link {url}"), + }, + "Library" => "https://gitlab.freedesktop.org/wayland/wayland", + _ => bail!("unhandled section {url}"), + } + } else if let Some(v) = url.strip_prefix("protocol-spec-") { + if let Some((interface, v)) = v.split_once("-") + && let Some((ty, message)) = v.split_once("-") + { + buf = format!("https://wayland.app/protocols/wayland#{interface}:{ty}:{message}"); + } else { + buf = format!("https://wayland.app/protocols/wayland#{v}"); + } + &buf + } else { + bail!("unknown link format {url}"); + }; + self.text.push_str("["); + self.text.push_str(text.trim()); + self.text.push_str("]"); + self.text.push_str("("); + self.text.push_str(url); + self.text.push_str(")"); + Ok(()) + } + + fn handle_ulink(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { + let mut text = String::new(); + loop { + let event = self.r.read_event().context("read event")?; + match event { + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + text.push_str(&s); + } + Event::End(v) if &*v == b"ulink" => break, + _ => bail!("unexpected event {event:?}"), + } + } + let url = e + .try_get_attribute("url") + .context("url")? + .context("url")? + .unescape_value() + .context("url")?; + self.text.push_str("["); + self.text.push_str(text.trim()); + self.text.push_str("]"); + self.text.push_str("("); + self.text.push_str(&url); + self.text.push_str(")"); + Ok(()) + } + + fn handle_code(&mut self) -> anyhow::Result<()> { + self.text.push_str("`"); + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + self.text.push_str(&s); + } + Event::End(v) if &*v == b"code" => break, + Event::End(v) if &*v == b"varname" => break, + Event::End(v) if &*v == b"literal" => break, + Event::End(v) if &*v == b"userinput" => break, + Event::End(v) if &*v == b"type" => break, + Event::End(v) if &*v == b"function" => break, + Event::End(v) if &*v == b"systemitem" => break, + _ => bail!("unexpected event {event:?}"), + } + } + self.text.push_str("`"); + Ok(()) + } + + fn handle_emphasis(&mut self) -> anyhow::Result<()> { + self.text.push_str("_"); + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + self.text.push_str(&s); + } + Event::End(v) if &*v == b"emphasis" => break, + Event::End(v) if &*v == b"firstterm" => break, + _ => bail!("unexpected event {event:?}"), + } + } + self.text.push_str("_"); + Ok(()) + } + + fn handle_newline(&mut self) -> anyhow::Result<()> { + if mem::take(&mut self.need_newline) { + self.write_line("")?; + } + Ok(()) + } + + fn write_line(&mut self, text: &str) -> anyhow::Result<()> { + self.handle_newline()?; + let text = text.trim_end(); + if text.is_empty() { + let indent = self.indent_1.trim_end(); + if indent.is_empty() { + if mem::take(&mut self.last_line_has_content) { + writeln!(self.w)?; + // dbg!(""); + } + } else { + writeln!(self.w, "{}", indent)?; + // dbg!("indent"); + self.last_line_has_content = true; + } + } else { + writeln!(self.w, "{}{text}", self.indent_1)?; + // dbg!(format!("{}{text}", self.indent_1)); + self.last_line_has_content = true; + } + self.clear_indent_1(); + Ok(()) + } + + fn clear_indent_1(&mut self) { + if self.have_indent_1 { + self.have_indent_1 = false; + self.indent_1.clone_from(&self.indent_2); + } + } + + fn push_indent( + &mut self, + indent: &str, + cont: bool, + f: impl FnOnce(&mut Self) -> anyhow::Result<()>, + ) -> anyhow::Result<()> { + self.handle_newline()?; + let len = self.indent_1.len(); + self.have_indent_1 = true; + self.indent_1.push_str(indent); + self.indent_1.push_str(" "); + if cont { + self.indent_2.push_str(indent); + self.indent_2.push_str(" "); + } else { + for _ in self.indent_2.len()..self.indent_1.len() { + self.indent_2.push_str(" "); + } + } + f(self)?; + self.indent_1.truncate(len); + self.indent_2.truncate(len); + Ok(()) + } + + fn flush_text(&mut self, synopsis: bool) -> anyhow::Result<()> { + const MAX_WIDTH: usize = 80; + self.handle_newline()?; + if synopsis { + self.write_line("```")?; + } + let text = mem::take(&mut self.text); + let trimmed = text.trim(); + if trimmed.is_not_empty() { + let options = Options::new(MAX_WIDTH) + .break_words(false) + .wrap_algorithm(WrapAlgorithm::FirstFit) + .word_separator(WordSeparator::AsciiSpace) + .word_splitter(WordSplitter::NoHyphenation) + .initial_indent(&self.indent_1) + .subsequent_indent(&self.indent_2); + let lines = textwrap::wrap(trimmed.trim(), options); + for line in lines { + writeln!(self.w, "{line}")?; + // dbg!(line); + self.last_line_has_content = true; + self.clear_indent_1(); + } + self.text = text; + } + if synopsis { + self.write_line("```")?; + } + self.text.clear(); + Ok(()) + } + + fn handle_admonition(&mut self, name: &str) -> anyhow::Result<()> { + self.push_indent(">", true, |slf| { + slf.write_line(&format!("[!{name}]"))?; + loop { + let event = slf.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(v) => match v.name().as_ref() { + b"simpara" | b"para" => slf.handle_para(false).context("handle_para")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::Text(t) if t.trim().is_empty() => {} + Event::End(v) if &*v == b"warning" => break, + Event::End(v) if &*v == b"note" => break, + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + }) + } + + fn handle_para(&mut self, synopsis: bool) -> anyhow::Result<()> { + self.handle_text_block(synopsis)?; + self.need_newline = true; + Ok(()) + } + + fn handle_text_block(&mut self, synopsis: bool) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(v) => match v.name().as_ref() { + b"synopsis" => { + self.flush_text(synopsis)?; + self.need_newline = true; + self.handle_para(true).context("handle_synopsis")? + } + b"emphasis" => self.handle_emphasis().context("handle_emphasis")?, + b"firstterm" => self.handle_emphasis().context("handle_firstterm")?, + b"type" => self.handle_code().context("handle_type")?, + b"code" => self.handle_code().context("handle_code")?, + b"systemitem" => self.handle_code().context("handle_systemitem")?, + b"function" => self.handle_code().context("handle_function")?, + b"filename" => self.handle_filename().context("handle_filename")?, + b"literal" => self.handle_code().context("handle_literal")?, + b"varname" => self.handle_code().context("handle_varname")?, + b"userinput" => self.handle_code().context("handle_userinput")?, + b"ulink" => self.handle_ulink(v).context("handle_ulink")?, + b"link" => self.handle_link(v).context("handle_link")?, + b"itemizedlist" => { + self.flush_text(synopsis)?; + self.need_newline = true; + self.handle_itemizedlist().context("handle_itemizedlist")? + } + b"orderedlist" => { + self.flush_text(synopsis)?; + self.need_newline = true; + self.handle_orderedlist().context("handle_orderedlist")? + } + b"variablelist" => { + self.flush_text(synopsis)?; + self.need_newline = true; + self.handle_variablelist().context("handle_variablelist")? + } + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::Empty(v) => match v.name().as_ref() { + b"xref" => self.handle_xref(v).context("handle_xref")?, + e => bail!("unexpected empty {:?}", e.as_bstr()), + }, + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + self.text.push_str(&s); + } + Event::GeneralRef(v) => { + self.text.push_str(&v.decode().unwrap()); + } + Event::End(v) if &*v == b"para" => break, + Event::End(v) if &*v == b"synopsis" => break, + Event::End(v) if &*v == b"simpara" => break, + Event::End(v) if &*v == b"literallayout" => break, + _ => bail!("unexpected event {event:?}"), + } + } + self.flush_text(synopsis)?; + Ok(()) + } + + fn handle_variablelist(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"title" => self.handle_title(TitleType::Bold).context("handle_title")?, + b"varlistentry" => self.handle_varlistentry().context("handle_varlistentry")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"variablelist" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_varlistentry(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"term" => self.handle_term().context("handle_term")?, + b"listitem" => self + .handle_listitem(ListType::Itemized) + .context("handle_listitem")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"varlistentry" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_term(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"literal" => self.handle_code().context("handle_literal")?, + b"synopsis" => self.handle_text_block(false).context("handle_synopsis")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"term" => break, + Event::Text(t) => { + let s = t.decode().unwrap(); + let s = WHITESPACE.replace_all(&s, " "); + self.text.push_str(&s); + } + _ => bail!("unexpected event {event:?}"), + } + } + self.flush_text(false)?; + Ok(()) + } + + fn handle_orderedlist(&mut self) -> anyhow::Result<()> { + let mut n = 1..; + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"listitem" => self + .handle_listitem(ListType::Numbered(n.next().unwrap())) + .context("handle_listitem")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"orderedlist" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_itemizedlist(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"listitem" => self + .handle_listitem(ListType::Bullet) + .context("handle_listitem")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"itemizedlist" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_listitem(&mut self, ty: ListType) -> anyhow::Result<()> { + let indent = match ty { + ListType::Bullet => Cow::Borrowed("-"), + ListType::Numbered(n) => Cow::Owned(format!("{n}.")), + ListType::Itemized => Cow::Borrowed(" :"), + }; + self.push_indent(&indent, false, |slf| { + loop { + let event = slf.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"simpara" | b"para" => slf.handle_para(false).context("handle_para")?, + b"warning" => slf.handle_admonition("WARNING").context("handle_warning")?, + b"note" => slf.handle_admonition("NOTE").context("handle_note")?, + b"variablelist" => { + slf.handle_variablelist().context("handle_variablelist")? + } + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"listitem" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + }) + } + + fn handle_figure(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"title" => self.handle_title(TitleType::Bold).context("handle_title")?, + b"mediaobject" | b"mediaobjectco" => { + self.handle_mediaobject().context("handle_mediaobject")? + } + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"figure" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_mediaobject(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"textobject" => self.handle_textobject().context("handle_textobject")?, + b"imageobject" => self.handle_imageobject().context("handle_imageobject")?, + b"imageobjectco" => self + .handle_imageobjectco() + .context("handle_imageobjectco")?, + b"caption" => self.handle_caption().context("handle_caption")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"mediaobject" => break, + Event::End(v) if &*v == b"mediaobjectco" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_textobject(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::End(v) if &*v == b"textobject" => break, + _ => {} + } + } + Ok(()) + } + + fn handle_imageobject(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"areaspec" => self.handle_areaspec().context("handle_areaspec")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::Empty(e) => match e.name().as_ref() { + b"imagedata" => self.handle_imagedata(e).context("handle_imagedata")?, + s => bail!("unexpected empty {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"imageobject" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_imageobjectco(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"areaspec" => self.handle_areaspec().context("handle_areaspec")?, + b"imageobject" => self.handle_imageobject().context("handle_imageobject")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"imageobjectco" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } + + fn handle_areaspec(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::End(v) if &*v == b"areaspec" => break, + _ => {} + } + } + Ok(()) + } + + fn handle_imagedata(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { + let fileref = e + .try_get_attribute("fileref") + .context("fileref")? + .context("fileref")? + .unescape_value() + .unwrap(); + self.write_line(&format!("![]({fileref})"))?; + self.need_newline = true; + Ok(()) + } + + fn handle_caption(&mut self) -> anyhow::Result<()> { + loop { + let event = self.r.read_event().context("read event")?; + // dbg!(&event); + match event { + Event::Start(e) => match e.name().as_ref() { + b"para" => self.handle_para(false).context("handle_para")?, + s => bail!("unexpected start {:?}", s.as_bstr()), + }, + Event::End(v) if &*v == b"caption" => break, + Event::Text(t) if t.trim().is_empty() => {} + _ => bail!("unexpected event {event:?}"), + } + } + Ok(()) + } +} From cff1224848c90137a45b3dde6a776711b81b6812 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 30 Jan 2026 21:06:25 +0100 Subject: [PATCH 1120/1152] doc: run docbook -> mdbook conversion tool To reproduce this commit, delete the contents of the src directory and run the tool. Signed-off-by: Julian Orth --- doc/book/.gitignore | 1 + doc/book/book.toml | 9 + doc/book/src/Architecture.md | 215 ++++++++++++++ doc/book/src/Color.md | 100 +++++++ doc/book/src/Compositors.md | 76 +++++ doc/book/src/Content_Updates.md | 214 ++++++++++++++ doc/book/src/Foreword.md | 11 + doc/book/src/Introduction.md | 73 +++++ doc/book/src/Message_XML.md | 493 ++++++++++++++++++++++++++++++++ doc/book/src/Protocol.md | 371 ++++++++++++++++++++++++ doc/book/src/SUMMARY.md | 12 + doc/book/src/Xwayland.md | 120 ++++++++ 12 files changed, 1695 insertions(+) create mode 100644 doc/book/.gitignore create mode 100644 doc/book/book.toml create mode 100644 doc/book/src/Architecture.md create mode 100644 doc/book/src/Color.md create mode 100644 doc/book/src/Compositors.md create mode 100644 doc/book/src/Content_Updates.md create mode 100644 doc/book/src/Foreword.md create mode 100644 doc/book/src/Introduction.md create mode 100644 doc/book/src/Message_XML.md create mode 100644 doc/book/src/Protocol.md create mode 100644 doc/book/src/SUMMARY.md create mode 100644 doc/book/src/Xwayland.md diff --git a/doc/book/.gitignore b/doc/book/.gitignore new file mode 100644 index 00000000..5a0bf031 --- /dev/null +++ b/doc/book/.gitignore @@ -0,0 +1 @@ +/book diff --git a/doc/book/book.toml b/doc/book/book.toml new file mode 100644 index 00000000..48f699ce --- /dev/null +++ b/doc/book/book.toml @@ -0,0 +1,9 @@ +[book] +title = "Wayland" +authors = ["Kristian Høgsberg"] +language = "en" + +[output.html] +git-repository-url = "https://gitlab.freedesktop.org/wayland/wayland" +edit-url-template = "https://gitlab.freedesktop.org/wayland/wayland/-/edit/main/doc/book/{path}" +site-url = "/docs/book/" diff --git a/doc/book/src/Architecture.md b/doc/book/src/Architecture.md new file mode 100644 index 00000000..2ecf38ac --- /dev/null +++ b/doc/book/src/Architecture.md @@ -0,0 +1,215 @@ +# Wayland Architecture + +## X vs. Wayland Architecture + +A good way to understand the Wayland architecture and how it is different from X +is to follow an event from the input device to the point where the change it +affects appears on screen. + +This is where we are now with X: + +**X architecture diagram** + +![](images/x-architecture.png) + +1. The kernel gets an event from an input device and sends it to X through the + evdev input driver. The kernel does all the hard work here by driving the + device and translating the different device specific event protocols to the + linux evdev input event standard. + +2. The X server determines which window the event affects and sends it to the + clients that have selected for the event in question on that window. The X + server doesn't actually know how to do this right, since the window location + on screen is controlled by the compositor and may be transformed in a number + of ways that the X server doesn't understand (scaled down, rotated, wobbling, + etc). + +3. The client looks at the event and decides what to do. Often the UI will have + to change in response to the event - perhaps a check box was clicked or the + pointer entered a button that must be highlighted. Thus the client sends a + rendering request back to the X server. + +4. When the X server receives the rendering request, it sends it to the driver + to let it program the hardware to do the rendering. The X server also + calculates the bounding region of the rendering, and sends that to the + compositor as a damage event. + +5. The damage event tells the compositor that something changed in the window + and that it has to recomposite the part of the screen where that window is + visible. The compositor is responsible for rendering the entire screen + contents based on its scenegraph and the contents of the X windows. Yet, it + has to go through the X server to render this. + +6. The X server receives the rendering requests from the compositor and either + copies the compositor back buffer to the front buffer or does a pageflip. In + the general case, the X server has to do this step so it can account for + overlapping windows, which may require clipping and determine whether or not + it can page flip. However, for a compositor, which is always fullscreen, this + is another unnecessary context switch. + +As suggested above, there are a few problems with this approach. The X server +doesn't have the information to decide which window should receive the event, +nor can it transform the screen coordinates to window-local coordinates. And +even though X has handed responsibility for the final painting of the screen to +the compositing manager, X still controls the front buffer and modesetting. Most +of the complexity that the X server used to handle is now available in the +kernel or self contained libraries (KMS, evdev, mesa, fontconfig, freetype, +cairo, Qt etc). In general, the X server is now just a middle man that +introduces an extra step between applications and the compositor and an extra +step between the compositor and the hardware. + +In Wayland the compositor is the display server. We transfer the control of KMS +and evdev to the compositor. The Wayland protocol lets the compositor send the +input events directly to the clients and lets the client send the damage event +directly to the compositor: + +**Wayland architecture diagram** + +![](images/wayland-architecture.png) + +1. The kernel gets an event and sends it to the compositor. This is similar to + the X case, which is great, since we get to reuse all the input drivers in + the kernel. + +2. The compositor looks through its scenegraph to determine which window should + receive the event. The scenegraph corresponds to what's on screen and the + compositor understands the transformations that it may have applied to the + elements in the scenegraph. Thus, the compositor can pick the right window + and transform the screen coordinates to window-local coordinates, by applying + the inverse transformations. The types of transformation that can be applied + to a window is only restricted to what the compositor can do, as long as it + can compute the inverse transformation for the input events. + +3. As in the X case, when the client receives the event, it updates the UI in + response. But in the Wayland case, the rendering happens in the client, and + the client just sends a request to the compositor to indicate the region that + was updated. + +4. The compositor collects damage requests from its clients and then + recomposites the screen. The compositor can then directly issue an ioctl to + schedule a pageflip with KMS. + +## Wayland Rendering + +One of the details I left out in the above overview is how clients actually +render under Wayland. By removing the X server from the picture we also removed +the mechanism by which X clients typically render. But there's another mechanism +that we're already using with DRI2 under X: direct rendering. With direct +rendering, the client and the server share a video memory buffer. The client +links to a rendering library such as OpenGL that knows how to program the +hardware and renders directly into the buffer. The compositor in turn can take +the buffer and use it as a texture when it composites the desktop. After the +initial setup, the client only needs to tell the compositor which buffer to use +and when and where it has rendered new content into it. + +This leaves an application with two ways to update its window contents: + +1. Render the new content into a new buffer and tell the compositor to use that + instead of the old buffer. The application can allocate a new buffer every + time it needs to update the window contents or it can keep two (or more) + buffers around and cycle between them. The buffer management is entirely + under application control. + +2. Render the new content into the buffer that it previously told the compositor + to to use. While it's possible to just render directly into the buffer shared + with the compositor, this might race with the compositor. What can happen is + that repainting the window contents could be interrupted by the compositor + repainting the desktop. If the application gets interrupted just after + clearing the window but before rendering the contents, the compositor will + texture from a blank buffer. The result is that the application window will + flicker between a blank window or half-rendered content. The traditional way + to avoid this is to render the new content into a back buffer and then copy + from there into the compositor surface. The back buffer can be allocated on + the fly and just big enough to hold the new content, or the application can + keep a buffer around. Again, this is under application control. + +In either case, the application must tell the compositor which area of the +surface holds new contents. When the application renders directly to the shared +buffer, the compositor needs to be noticed that there is new content. But also +when exchanging buffers, the compositor doesn't assume anything changed, and +needs a request from the application before it will repaint the desktop. The +idea that even if an application passes a new buffer to the compositor, only a +small part of the buffer may be different, like a blinking cursor or a spinner. + +## Accelerated GPU Buffer Exchange + +Clients +[exchange](https://docs.kernel.org/userspace-api/dma-buf-alloc-exchange.html) +GPU buffers with the compositor as dma-buf file descriptors, which are universal +handles that are independent of any particular rendering API or memory +allocator. The +[linux-dmabuf-v1](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/stable/linux-dmabuf/linux-dmabuf-v1.xml) +protocol is used to turn one or more dma-buf FDs into a +[wl_buffer](https://wayland.app/protocols/wayland#wl_buffer). + +If the client uses the +[Vulkan](https://docs.vulkan.org/spec/latest/chapters/VK_KHR_surface/wsi.html) +or +[EGL](https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_platform_wayland.txt) +(via +[wayland-egl](https://gitlab.freedesktop.org/wayland/wayland/-/tree/main/egl)) +window-system integration (WSI), this is done transparently by the WSI. + +Clients can alternatively allocate and import dma-bufs themselves using the GBM +library, Vulkan, udmabuf, or dma-buf heaps. + +- Using GBM, the client can allocate a gbm_bo and export one or more dma-buf FDs + from it. + +- Using Vulkan, the client can create a VkDeviceMemory object and use + [VK_EXT_external_memory_dma_buf](https://docs.vulkan.org/refpages/latest/refpages/source/VK_EXT_external_memory_dma_buf.html) + and + [VK_EXT_image_drm_format_modifier](https://docs.vulkan.org/refpages/latest/refpages/source/VK_EXT_image_drm_format_modifier.html) + to export a dma-buf FD from it. + +- [udmabuf](https://lwn.net/Articles/749206/) can be used to create dma-buf FDs + from linear host memory. + +- [Dma-buf heaps](https://docs.kernel.org/userspace-api/dma-buf-heaps.html) can + be used by privileged applications to create dma-buf FDs on embedded devices. + +Compositors use +[VK_EXT_external_memory_dma_buf](https://docs.vulkan.org/refpages/latest/refpages/source/VK_EXT_external_memory_dma_buf.html) +and +[VK_EXT_image_drm_format_modifier](https://docs.vulkan.org/refpages/latest/refpages/source/VK_EXT_image_drm_format_modifier.html) +or +[EGL_EXT_image_dma_buf_import](https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt) +and +[EGL_EXT_image_dma_buf_import_modifiers](https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt) +to import the dma-bufs provided by the client into their own Vulkan or EGL +renderers. + +Clients do not need to wait for the GPU to finish rendering before submitting +dma-bufs to the compositor. Clients can use the +[linux-drm-syncobj-v1](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml) +protocol to exchange DRM synchronization objects with the compositor. These +objects are used to asynchronously signal ownership transfer of buffers from +clients to the compositor and vice versa. The WSIs do this transparently. + +If the linux-drm-syncobj-v1 protocol is not supported by the compositor, clients +and compositors can use the +[DMA_BUF_IOCTL_EXPORT_SYNC_FILE](https://docs.kernel.org/driver-api/dma-buf.html#c.dma_buf_export_sync_file) +and +[DMA_BUF_IOCTL_IMPORT_SYNC_FILE](https://docs.kernel.org/driver-api/dma-buf.html#c.dma_buf_import_sync_file) +ioctls to access and create implicit synchronization barriers. + +## Display Programming + +Compositors enumerate DRM KMS devices using +[udev](https://en.wikipedia.org/wiki/Udev). Udev also notifies compositors of +KMS device and display hotplug events. + +Access to DRM KMS device ioctls is privileged. Since compositors usually run as +unprivileged applications, they typically gain access to a privileged file +descriptor using the +[TakeDevice](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html#Session%20Objects) +method provided by logind. + +Using the file descriptor, compositors use KMS +[ioctls](https://docs.kernel.org/gpu/drm-kms.html) to enumerate the available +displays. + +Compositors use [atomic mode +setting](https://docs.kernel.org/gpu/drm-kms.html#atomic-mode-setting) to change +the buffer shown by the display, to change the display's resolution, to enable +or disable HDR, and so on. diff --git a/doc/book/src/Color.md b/doc/book/src/Color.md new file mode 100644 index 00000000..3787108b --- /dev/null +++ b/doc/book/src/Color.md @@ -0,0 +1,100 @@ +# Color management + +## Overview + +Color management in Wayland considers only displays. All pictures in Wayland are +always display-referred, meaning that the pixel values are intended as-is for +some specific display where they would produce the light emissions +([stimuli](https://cie.co.at/eilvterm/17-23-002)) the picture's author desired. +Wayland does not support displaying "raw" camera or scanner images as they are +not display-referred, nor are they even pictures without complex and subjective +processing. + +Stimuli — the picture itself — are only half of the picture reproduction. The +other half is the environment where a display is viewed. A striking example is +comparing a brightly lit office to a dark movie theater, the stimuli required to +produce a good reading of the picture is greatly different. Therefore +display-referred does not include only the display but the viewing environment +as well. + +Window systems have been very well capable of operating without any explicit +consideration to color management. This is because there used to be the implicit +assumption of the standard display, the sRGB display, which all computer +monitors implemented, more or less. The viewing environment was and still is +accounted by adjusting the display and/or the room to produce a workable +experience. Pictures are authored on a computer system by drawing, painting and +adjusting the picture until it looks right on the author's monitor. This +implicitly builds the standard display and environment assumption into the +picture data. Deviations from the sRGB specification were minor enough that they +often did not matter if not in a professional context like the printing +industry. Displaying video material required some more attention to the details, +because video and television standards differ enough from the sRGB display. What +really made explicit color management a hard requirement for entertainment is +the coming of wide color gamut (WCG) and high dynamic range (HDR) materials and +displays. + +The color management design in Wayland follows the general Wayland design +principles: compositors tell clients what would be the optimal thing to do, +clients tell the compositors what kind of pictures they are actually producing, +and then compositors display those pictures the best they can. + +## Protocol Interfaces + +Color management interfaces in Wayland and divided into two protocols: +[color-management](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/color-management?ref_type=heads) +and +[color-representation](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/color-representation?ref_type=heads). +They are designed to work together, but they can also be used independently when +the other one is not needed. + +### Color-management + +Color management protocol has two main purposes. First, it puts the +responsibility of color management on the compositor. This means that clients do +not necessarily need to care about color management at all, and can display just +fine by using the traditional standard display assumption even when the actual +display is wildly different. Clients can also choose to target some other +assumed display and let the compositor handle it, or they can explicitly render +for the actual display at hand. Second, when the window system has multiple +different monitors, and a wl_surface happens to span more than one monitor, the +compositor can display the surface content correctly on all spanned monitors +simultaneously, as much as physically possible. + +Color-management protocol concentrates on colorimetry: when you have a pixel +with RGB values, what stimulus do those values represent. The stimulus +definition follows the CIE 1931 two-degree observer model. Some core concepts +here are color primaries, white point, transfer function, and dynamic range. The +viewing environment is represented in an extremely simplified way as the +reference white luminance. The connection between pixel RGB values and stimulus +plus viewing environment is recorded in an _image description_ object. Clients +can create image description objects and tag `wl_surface`s with them, to +indicate what kind of surface content there will be. Clients can also ask what +image description the compositor would prefer to have on the `wl_surface`, and +that preference can change over time, e.g. when the `wl_surface` is moved from +one `wl_output` to another. Following the compositor's preference may provide +advantages in image quality and power consumption. + +Image description objects can come in two flavors: parametric and ICC-based. The +above was written with parametric image descriptions in mind, and they have +first-class support for HDR. ICC-based image descriptions are wrapping an ICC +profile and have no other data. ICC profiles are the standard tool for standard +dynamic range (SDR) display color management. This means the capabilities +between the two flavors differ, and one cannot always be replaced by the other. +Compositor support for each flavor is optional. + +### Color-representation + +Color-representation protocol deals with (potentially sub-sampled) YCbCr-RGB +conversion, quantization range, and the inclusion of alpha in the RGB color +channels, a.k.a. pre-multiplication. There are several different specifications +on how an YCbCr-like (including ICtCp) signal, with chroma sub-sampling or not, +is created from a full-resolution RGB image. Again, a client can tag a +`wl_surface` with color-representation metadata to tell the compositor what kind +of pixel data will be displayed through the wl_surface. + +The main purpose of color-representation is to correctly off-load the YCbCr-RGB +conversion to the compositor, which can then opportunistically off-load it +further to very power-efficient fixed-function circuitry in a display +controller. This can significantly reduce power consumption when watching videos +compared to using a GPU for the same, and on some embedded hardware platforms it +is a hard requirement for processing high resolution video. diff --git a/doc/book/src/Compositors.md b/doc/book/src/Compositors.md new file mode 100644 index 00000000..251be316 --- /dev/null +++ b/doc/book/src/Compositors.md @@ -0,0 +1,76 @@ +# Types of Compositors + +Compositors come in different types, depending on which role they play in the +overall architecture of the OS. For instance, a [system +compositor](#system-compositor) can be used for booting the system, handling +multiple user switching, a possible console terminal emulator and so forth. A +different compositor, a [session compositor](#session-compositor) would provide +the actual desktop environment. There are many ways for different types of +compositors to co-exist. + +In this section, we introduce three types of Wayland compositors relying on +[libwayland-server](https://gitlab.freedesktop.org/wayland/wayland). + +## System Compositor + +A system compositor can run from early boot until shutdown. It effectively +replaces the kernel vt system, and can tie in with the systems graphical boot +setup and multiseat support. + +A system compositor can host different types of session compositors, and let us +switch between multiple sessions (fast user switching, or secure/personal +desktop switching). + +A linux implementation of a system compositor will typically use libudev, egl, +kms, evdev and cairo. + +For fullscreen clients, the system compositor can reprogram the video scanout +address to read directly from the client provided buffer. + +## Session Compositor + +A session compositor is responsible for a single user session. If a system +compositor is present, the session compositor will run nested under the system +compositor. Nesting is feasible because the protocol is asynchronous; roundtrips +would be too expensive when nesting is involved. If no system compositor is +present, a session compositor can run directly on the hardware. + +X applications can continue working under a session compositor by means of a +root-less X server that is activated on demand. + +Possible examples for session compositors include + +- gnome-shell + +- moblin + +- kwin + +- kmscon + +- rdp session + +- Weston with X11 or Wayland backend is a session compositor nested in another + session compositor. + +- fullscreen X session under Wayland + +## Embedding Compositor + +X11 lets clients embed windows from other clients, or lets clients copy pixmap +contents rendered by another client into their window. This is often used for +applets in a panel, browser plugins and similar. Wayland doesn't directly allow +this, but clients can communicate GEM buffer names out-of-band, for example, +using D-Bus, or command line arguments when the panel launches the applet. +Another option is to use a nested Wayland instance. For this, the Wayland server +will have to be a library that the host application links to. The host +application will then pass the Wayland server socket name to the embedded +application, and will need to implement the Wayland compositor interface. The +host application composites the client surfaces as part of it's window, that is, +in the web page or in the panel. The benefit of nesting the Wayland server is +that it provides the requests the embedded client needs to inform the host about +buffer updates and a mechanism for forwarding input events from the host +application. + +An example for this kind of setup is firefox embedding the flash player as a +kind of special-purpose compositor. diff --git a/doc/book/src/Content_Updates.md b/doc/book/src/Content_Updates.md new file mode 100644 index 00000000..91d290f0 --- /dev/null +++ b/doc/book/src/Content_Updates.md @@ -0,0 +1,214 @@ +# Content Updates + +## Overview + +In the Wayland protocol, requests are asynchronous but take effect immediately +when the compositor receives them. However, some requests on surfaces are not +applied immediately but are instead double-buffered to allow atomic changes. +These double-buffered changes are committed through the wl_surface.commit +request, which creates a Content Update. + +Content Updates encapsulate all double-buffered state changes and can be applied +by the compositor. The complexity arises when considering subsurfaces, which can +operate in synchronized mode. When a subsurface is synchronized, its Content +Updates must be applied atomically together with the parent surface's state. +This synchronization can extend through an entire tree of subsurfaces, where +child subsurfaces inherit the synchronized behavior from their parents. + +Historically, Content Updates from synchronized subsurfaces were merged into the +pending state of the parent surface on commit. However, the introduction of +constraints—which can defer the application of Content Updates—necessitated a +more sophisticated model. This led to the implementation of per-surface queues +of Content Updates, with dependencies between Content Updates across different +queues. This queuing model maintains backwards compatibility with the earlier +approach of merging Content Updates into the parent's pending state on commit. + +The core protocol defines the semantics of Content Updates using per-surface +queues, but compositors that do not need to support constraints may implement +the simpler legacy model where synchronized subsurface states are merged +directly into the parent's pending state. + +## Rules + +The core protocol specifies the behavior in wl_subsurface and wl_surface.commit. +The behavior can be summarized by the following rules: + +1. Content Updates (CU) contain all double-buffered state of the surface and + selected state from their direct children. + +2. Surfaces which are effectively synchronized create Synchronized Content + Updates (SCU), otherwise they create Desync Content Updates (DCU). + +3. When a CU is created, it gets a dependency on the previous CU of the same + queues (if it exists). + +4. When a CU is created, it gets a dependency on the last SCU of direct child + surfaces that are not reachable (if they exists). + +5. The CUs and their dependencies form a DAG, where CUs are nodes and + dependencies are edges. + +6. All DCUs starting from the front of the queues until the first SCU or the + back of the queue is reached are candidates. + +7. If the maximal DAG that's reachable from a candidate (candidate DAG) does not + have any constraints, then this DAG can be applied. + +8. A DAG is applied atomically by recursively applying a content update without + dependencies and removing it from the DAG. + +9. Surfaces transition from effectively sync to effectively desync after their + parents. + +10. When a surface transitions to effectively desync, all SCUs in its queue + which are not reachable by a DCU become DCUs. + +## Examples + +These examples should help to build an intuition for how content updates +actually behave. They cover the interesting edge cases, such as subsurfaces with +constraints, and transitioning from a sync subsurface to a desync one. + +In all the examples below, the surface T1 refers to a toplevel surface, SS1 +refers to a sub-surface which is a child of T1, and SS2 refers to a sub-surface +which is a child of SS1. + +**Legend** + +![](images/content-updates/content-update-legend.png) + +**Simple Desynchronized Case** + +![](images/content-updates/simple-desynchronized-state-1.png) + +SS2 is effectively desynchronized and commits. This results in the +desynchronized content update (DCU) _1_. + +![](images/content-updates/simple-desynchronized-state-2.png) + +DCU _1_ is a candidate, and the candidate DAG reachable from DCU _1_ is only DCU +_1_ itself. DCU _1_ and thus the candidate DAG does not have any constraints and +can be applied. + +![](images/content-updates/simple-desynchronized-state-3.png) + +The content updates of the candidate DAG get applied to the surface atomically. + +![](images/content-updates/simple-desynchronized-state-4.png) + +T1 commits a DCU with a _buffer-sync_ constraint. It is a candidate but its DAG +can't be applied because it contains a constraint. + +![](images/content-updates/simple-desynchronized-state-5.png) + +T1 commits another CU (DCU _3_) which is added at the end of the queue, with a +dependency to the previous CU (DCU _2_). Both DCU _2_ and DCU _3_ are +candidates, but both DAGs contain DCU _2_ with a constraint, and can't be +applied. + +![](images/content-updates/simple-desynchronized-state-6.png) + +When the constraint gets cleared, both DAGs can be applied to the surface +atomitcally (either only _2_, or _2_ and _3_). + +**Simple Synchronized Case** + +![](images/content-updates/simple-synchronized-state-1.png) + +SS1 and SS2 are effectively synchronized. SS2 commits SCU _1_. + +![](images/content-updates/simple-synchronized-state-2.png) + +SS1 commits SCU _2_. The direct child surfaces SS2 has the last SCU _1_ in its +queue, which is not reachable. This creates a dependency from SCU _2_ to SCU +_1_. + +![](images/content-updates/simple-synchronized-state-3.png) + +SS1 commits SCU _3_. The direct child surfaces SS2 has the last SCU _1_ in its +queue, which is already reachable by SCU _2_. No dependency to SCU _1_ is +created. A dependency to the previous CU of the same queue (SCU _2_) is created. + +![](images/content-updates/simple-synchronized-state-4.png) + +T1 commit DCU _4_. It is a candidate, its DAG does not contain any constraint +and it can be applied. + +![](images/content-updates/simple-synchronized-state-5.png) + +The DAG gets applied to the surfaces atomically. + +**Complex Synchronized Subsurface Case 1** + +![](images/content-updates/sync-subsurf-case1-1.png) + +Every DCU (_1_ and _6_) contain CUs with constraints in their candidate DAG + +![](images/content-updates/sync-subsurf-case1-2.png) + +Waiting until the _buffer-sync_ constrain on CU _1_ is cleared, the candidate +DAG of CU _1_ does not contain constraints and can be applied + +![](images/content-updates/sync-subsurf-case1-3.png) + +That leaves the candidate DAG of CU _6_ which still contains another CU with a +_buffer-sync_ constrain + +![](images/content-updates/sync-subsurf-case1-4.png) + +Waiting until the _buffer-sync_ constrain on CU _6_ is cleared, the candidate +DAG of _6_ does not contain CUs with constraints and can be applied. + +![](images/content-updates/sync-subsurf-case1-5.png) + +There is no DCU left and no constraint remaining. Nothing more can be applied +without a new CU. + +**Complex Synchronized Subsurface Case 2** + +![](images/content-updates/sync-subsurf-case2-1.png) + +Both DCUs (_1_ and _6_) have a reachable DAG containing CU _1_ with a constraint + +![](images/content-updates/sync-subsurf-case2-2.png) + +Waiting until the _buffer-sync_ constrain on _1_ is cleared, both DAGs contain +no CU with constraints and can be applied in any order + +![](images/content-updates/sync-subsurf-case2-3.png) + +That leaves the same state as in the previous case + +**Synchronized to Desynchronized Subsurface** + +![](images/content-updates/sync-to-desync-subsurf-1.png) + +There is one DCU (_4_) with its reachable DAG that cannot be applied because CU +_4_ contains a constraint + +![](images/content-updates/sync-to-desync-subsurf-2.png) + +Surface _SS1_ transitions from effectively synchronized to effectively +desynchronized. SCU _2_ is reachable by DCU _4_ so nothing changes. + +![](images/content-updates/sync-to-desync-subsurf-3.png) + +Surface _SS1_ provides a new DCU (_5_) but because the CU before (_2_) is a +Synchronized CU, it is not a candidate + +**Synchronized to Desynchronized Transition** + +![](images/content-updates/sync-to-desync-transition-1.png) + +There are four SCUs and all surfaces are effectively synchronized. + +![](images/content-updates/sync-to-desync-transition-2.png) + +Surface _SS1_ transitions to effectively desynchronized and SCU _2_ becomes a +DCU because it is not reachable from a DCU + +![](images/content-updates/sync-to-desync-transition-3.png) + +Surface _SS2_ transitions to effectively desynchronized. SCUs _3_ and _4_ become +DCUs because they are not reachable from a DCU. SCU _1_ does not change because +it is reachable by DCU _2_. diff --git a/doc/book/src/Foreword.md b/doc/book/src/Foreword.md new file mode 100644 index 00000000..48cadf6e --- /dev/null +++ b/doc/book/src/Foreword.md @@ -0,0 +1,11 @@ +# Preface + +This document describes the (i) Wayland architecture, (ii) Wayland model of +operation and (iii) its library API. Also, the Wayland protocol specification is +shown in the Appendix. This document is aimed primarily at Wayland developers +and those looking to program with it; it does not cover application development. + +There have been many contributors to this document and since this is only the +first edition many errors are expected to be found. We appreciate corrections. + +Yours, the Wayland open-source community November 2012 diff --git a/doc/book/src/Introduction.md b/doc/book/src/Introduction.md new file mode 100644 index 00000000..51ef7a01 --- /dev/null +++ b/doc/book/src/Introduction.md @@ -0,0 +1,73 @@ +# Introduction + +## Motivation + +Most Linux and Unix-based systems rely on the X Window System (or simply _X_) as +the low-level protocol for building bitmap graphics interfaces. On these +systems, the X stack has grown to encompass functionality arguably belonging in +client libraries, helper libraries, or the host operating system kernel. Support +for things like PCI resource management, display configuration management, +direct rendering, and memory management has been integrated into the X stack, +imposing limitations like limited support for standalone applications, +duplication in other projects (e.g. the Linux fb layer or the DirectFB project), +and high levels of complexity for systems combining multiple elements (for +example radeon memory map handling between the fb driver and X driver, or VT +switching). + +Moreover, X has grown to incorporate modern features like offscreen rendering +and scene composition, but subject to the limitations of the X architecture. For +example, the X implementation of composition adds additional context switches +and makes things like input redirection difficult. + +![](images/x-architecture.png) + +The diagram above illustrates the central role of the X server and compositor in +operations, and the steps required to get contents on to the screen. + +Over time, X developers came to understand the shortcomings of this approach and +worked to split things up. Over the past several years, a lot of functionality +has moved out of the X server and into client-side libraries or kernel drivers. +One of the first components to move out was font rendering, with freetype and +fontconfig providing an alternative to the core X fonts. Direct rendering OpenGL +as a graphics driver in a client side library went through some iterations, +ending up as DRI2, which abstracted most of the direct rendering buffer +management from client code. Then cairo came along and provided a modern 2D +rendering library independent of X, and compositing managers took over control +of the rendering of the desktop as toolkits like GTK+ and Qt moved away from +using X APIs for rendering. Recently, memory and display management have moved +to the Linux kernel, further reducing the scope of X and its driver stack. The +end result is a highly modular graphics stack. + +## The compositing manager as the display server + +Wayland is a new display server and compositing protocol, and Weston is the +implementation of this protocol which builds on top of all the components above. +We are trying to distill out the functionality in the X server that is still +used by the modern Linux desktop. This turns out to be not a whole lot. +Applications can allocate their own off-screen buffers and render their window +contents directly, using hardware accelerated libraries like libGL, or high +quality software implementations like those found in Cairo. In the end, what’s +needed is a way to present the resulting window surface for display, and a way +to receive and arbitrate input among multiple clients. This is what Wayland +provides, by piecing together the components already in the eco-system in a +slightly different way. + +X will always be relevant, in the same way Fortran compilers and VRML browsers +are, but it’s time that we think about moving it out of the critical path and +provide it as an optional component for legacy applications. + +Overall, the philosophy of Wayland is to provide clients with a way to manage +windows and how their contents are displayed. Rendering is left to clients, and +system wide memory management interfaces are used to pass buffer handles between +clients and the compositing manager. + +![](images/wayland-architecture.png) + +The figure above illustrates how Wayland clients interact with a Wayland server. +Note that window management and composition are handled entirely in the server, +significantly reducing complexity while marginally improving performance through +reduced context switching. The resulting system is easier to build and extend +than a similar X system, because often changes need only be made in one place. +Or in the case of protocol extensions, two (rather than 3 or 4 in the X case +where window management and/or composition handling may also need to be +updated). diff --git a/doc/book/src/Message_XML.md b/doc/book/src/Message_XML.md new file mode 100644 index 00000000..47b37796 --- /dev/null +++ b/doc/book/src/Message_XML.md @@ -0,0 +1,493 @@ +# Message Definition Language + +## Overview + +The fundamentals of the Wayland protocol are explained in [Wayland Protocol and +Model of Operation](Protocol.md). This chapter formally defines the language +used to define Wayland protocols. + +Wayland is an object-oriented protocol. Each object follows exactly one +interface. An interface is a collection of message and enumeration definitions. +A message can be either a request (sent by a client) or an event (sent by a +server). A message can have arguments. All arguments are typed. + +## XML Elements + +### protocol + +``` +protocol ::= (copyright?, description? interface+) +``` + +`protocol` is the root element in a Wayland protocol XML file. Code generation +tools may optionally use the protocol `name` in API symbol names. The XML file +name should be similar to the protocol name. + +The description element should be used to document the intended purpose of the +protocol, give an overview, and give any development stage notices if +applicable. + +The copyright element should be used to indicate the copyrights and the license +of the XML file. + +**Required attributes** + +`name`="`cname`" + : The name of the protocol (a.k.a protocol extension). cname-requirements + + The name should be globally unique. Protocols to be included in + [wayland-protocols](https://gitlab.freedesktop.org/wayland/wayland-protocols) + must follow the naming rules set there. Other protocols should use a unique + prefix for the name, e.g. referring to the owning project's name. + +### copyright + +Parent elements: protocol + +``` +copyright ::= #PCDATA +``` + +Contains free-form, pre-formatted text for copyright and license notices. + +### description + +Parent elements: protocol, interface, request, event, arg, enum, entry + +``` +description ::= #PCDATA +``` + +Contains human-readable documentation for its parent element. May contain +formatted text, including paragraphs and bulleted lists. + +**Optional attributes** + +`summary`="`summary`" + : A short (half a line at most) description of the documented element. + + When a description element is used, it is recommended to not use the + `summary` attribute of the parent element. + +### interface + +Parent elements: protocol + +``` +interface ::= (description?, (request|event|enum)+) +``` + +An interface element contains the requests and events that form the interface. +Enumerations can also be defined with enum elements. These all belong into the +namespace of the interface. Code generation tools may use the interface `name` +in API symbol names. + +Interfaces form an ancestry tree. Aside from +[wl_display](https://wayland.app/protocols/wayland#wl_display), new protocol +objects are always created through an existing protocol object that may be +referred to as _the factory object_. This can happen in one of two ways: the +factory object's interface either defines or does not define the new object's +interface. + +When the factory interface defines the new object's interface, the new object +also inherits the factory object's interface version number. This number defines +the interface version of the new object. The factory object is referred to as +_the parent object_ and the factory interface is referred to as _the parent +interface_. This forms the ancestry tree of interfaces. + +When the factory interface does not define the new object's interface, both the +interface name and the version must be communicated explicitly. The foremost +example of this is +[wl_registry.bind](https://wayland.app/protocols/wayland#wl_registry:request:bind). +In this case the terms "parent" or "ancestor" are not used. Interfaces that are +advertised through +[wl_registry](https://wayland.app/protocols/wayland#wl_registry) are called +_global interfaces_, or globals for short. + +If objects having the interface can cause protocol errors, the protocol error +codes must be defined within the interface with an enum element with its `name` +set to `"error"`. Protocol error codes are always specific to the interface of +the object referred to in +[wl_display.error](https://wayland.app/protocols/wayland#wl_display:event:error). + +The description element should be used to describe the purpose and the general +usage of the interface. + +**Required attributes** + +`name`="`cname`" + : The name of the interface. cname-requirements The name must be unique in the + protocol, and preferably it should also be globally unique to avoid API + conflicts in language bindings of multiple protocols. + + Protocols to be included in + [wayland-protocols](https://gitlab.freedesktop.org/wayland/wayland-protocols) + must follow the interface naming rules set there. Other protocols should use + a unique prefix for the name, e.g. referring to the owning project's name. + +`version`="`V`" + : The interface's latest version number `V` must be an integer greater than + zero. An interface element defines all versions of the interface from 1 to + `V` inclusive. The contents of each interface version are defined in each of + the request, event, enum and entry elements using the attributes `since` and + `deprecated-since`, and in the specification text. + + When an interface is extended, the version number must be incremented on all + the interfaces part of the same interface ancestry tree. The exception to + this rule are interfaces which are forever stuck to version 1, which is + usually caused by having multiple parent interfaces with independent + ancestor global interfaces. + + A protocol object may have any defined version of the interface. The version + of the object is determined at runtime either by inheritance from another + protocol object or explicitly. + + It is possible for a protocol object to have a version higher than defined + by its interface. This may happen when the interface is stuck at version 1 + as per above. It may also happen when a protocol XML file has not been + thoroughly updated as required. In such cases the object shall function as + with the highest defined interface version. + +### request + +Parent elements: interface + +``` +request ::= (description?, arg*) +``` + +Defines a request, a message from a client to a server. Requests are always +associated with a specific protocol object. + +Requests are automatically assigned opcodes in the order they appear inside the +interface element. Therefore the only backwards-compatible way to add requests +to an interface is to add them to the end. Any event elements do not interfere +with request opcode assignments. + +The arg elements declare the request's arguments. There can be 0 to 20 arguments +for a request. The order of arg inside the request element defines the order of +the arguments on the wire. All declared arguments are mandatory, and extra +arguments are not allowed on the wire. + +The description element should be used to document the request. + +**Required attributes** + +`name`="`cname`" + : The name of the request. cname-requirements The name must be unique within + all requests and events in the containing interface. + + Code and language binding generators may use the name in the API they + create. The `name` of the containing interface provides the namespace for + requests. + +**Optional attributes** + +`type`="`destructor`" + : When this attribute is present, the request is a destructor: it shall + destroy the protocol object it is sent on. Protocol IPC libraries may use + this for bookkeeping protocol object lifetimes. + + Libwayland-client uses this information to ignore incoming events for + destroyed protocol objects. Such events may occur due to a natural race + condition between the client destroying a protocol object and the server + sending events before processing the destroy request. + +`since`="`S`" + : `S` must be an integer greater than zero. If `since` is not specified, + `since="1"` is assumed. + + This request was added in interface `version` `S`. The request does not + exist if the protocol object has a bound version smaller than `S`. Attempts + to use it in such a case shall raise the protocol error + `wl_display.error.invalid_method`. + +`deprecated-since`="`D`" + : `D` must be an integer greater than the value of `since`. If + `deprecated-since` is not specified, then the request is not deprecated in + any version of the containing interface. + + This request was deprecated in interface `version` `D` and above, and should + not be sent on protocol objects of such version. This is informational. + Compositors must still be prepared to handle the request unless specified + otherwise. + +### event + +Parent elements: interface + +``` +event ::= (description?, arg*) +``` + +Defines an event, a message from a server to a client. Events are always +associated with a specific protocol object. + +Events are automatically assigned opcodes in the order they appear inside the +interface element. Therefore the only backwards-compatible way to add events to +an interface is to add them to the end. Any request elements do not interfere +with event opcode assignments. + +The arg elements declare the event's arguments. There can be 0 to 20 arguments +for an event. The order of arg inside the event element defines the order of the +arguments on the wire. All declared arguments are mandatory, and extra arguments +are not allowed on the wire. + +The description element should be used to document the event. + +**Required attributes** + +`name`="`cname`" + : The name of the event. cname-requirements The name must be unique within all + requests and events in the containing interface. + + Code and language binding generators may use the name in the API they + create. The `name` of the containing interface provides the namespace for + events. + +**Optional attributes** + +`type`="`destructor`" + : When this attribute is present, the event is a destructor: it shall destroy + the protocol object it is sent on. Protocol IPC libraries may use this for + bookkeeping protocol object lifetimes. + + > [!WARNING] + > Destructor events are an underdeveloped feature in Wayland. They can be + > used only on client-created protocol objects, and it is the protocol + > designer's responsibility to design such a message exchange that race + > conditions cannot occur. The main problem would be a client sending a + > request at the same time as the server is sending a destructor event. The + > server will consider the protocol object to be already invalid or even + > recycled when it proceeds to process the request. This often results in + > protocol errors, but under specific conditions it might also result in + > silently incorrect behavior. + > + > Destructor events should not be used in new protocols. If a destructor + > event is necessary, the simplest way to avoid these problems is to have + > the interface not contain any requests. + +`since`="`S`" + : `S` must be an integer greater than zero. If `since` is not specified, + `since="1"` is assumed. + + This event was added in interface `version` `S`. The event does not exist if + the protocol object has a bound version smaller than `S`. + +`deprecated-since`="`D`" + : `D` must be an integer greater than the value of `since`. If + `deprecated-since` is not specified, then the event is not deprecated in any + version of the containing interface. + + This event was deprecated in interface `version` `D` and above, and should + not be sent on protocol objects of such version. This is informational. + Clients must still be prepared to receive this event unless otherwise + specified. + +### arg + +Parent elements: request, event + +``` +arg ::= description? +``` + +This element declares one argument for the request or the event. + +**Required attributes** + +`name`="`cname`" + : The name of the argument. cname-requirements The name must be unique within + all the arguments of the parent element. + +`type`="`T`" + : The type `T` of the argument datum must be one of: + + `int` + : 32-bit signed integer. + + `uint` + : 32-bit unsigned integer. + + `fixed` + : Signed 24.8-bit fixed-point value. + + `string` + : UTF-8 encoded string value, NUL byte terminated. Interior NUL bytes are + not allowed. + + `array` + : A byte array of arbitrary data. + + `fd` + : A file descriptor. + + The file descriptor must be open and valid on send. It is not possible + to pass a null value. + + `new_id` + : Creates a new protocol object. A request or an event may have at most + one `new_id` argument. + + If `interface` is specified, the new protocol object shall have the + specified interface, and the new object's (interface) version shall be + the version of the object on which the request or event is being sent. + + If `interface` is not specified, the request shall implicitly have two + additional arguments: A `string` for an interface name, and a `uint` for + the new object's version. Leaving the interface unspecified is reserved + for special use, + [wl_registry.bind](https://wayland.app/protocols/wayland#wl_registry:request:bind) + for example. + + > [!NOTE] + > An event argument must always specify the `new_id` `interface`. + + `object` + : Reference to an existing protocol object. + + The attribute `interface` should be specified. Otherwise IPC libraries + cannot enforce the interface, and checking the interface falls on user + code and specification text. + +**Optional attributes** + +`summary`="`summary`" + : A short (half a line at most) description. This attribute should not be used + if a description is used. + +`interface`="`iface`" + : If given, `iface` must be the `name` of some interface, and `type` of this + argument must be either `"object"` or `"new_id"`. This indicates that the + existing or new object must have the interface `iface`. Use for other + argument types is forbidden. + + > [!NOTE] + > If an interface from another protocol is used, then this creates a + > dependency between the protocols. If an application generates code for one + > protocol, then it must also generate code for all dependencies. Therefore + > this would not be a backwards compatible change. + +`allow-null`="`true`" | "`false`" + : Whether the argument value can be null on send. Defaults to `"false"`, + meaning it is illegal to send a null value. Can be used only when `type` is + `"string"` or `"object"`. + + > [!NOTE] + > Even though this attribute can be used to forbid a compositor from sending + > a null object as an event argument, an IPC library implementation may not + > protect the client from receiving a null object. This can happen with + > libwayland-client when the client has destroyed the protocol object before + > dispatching an event that referred to it in an argument. + +`enum`="`enum-cname-suffix`" + : If specified, indicates that the argument value should come from the enum + named `enum-cname-suffix`. If the enumeration is a bitfield, then `type` + must be `"uint"`. Otherwise `type` must be either `"uint"` or `"int"`. + + The name `enum-cname-suffix` refers to an enum in the same interface by + default. If it is necessary to refer to an enumeration from another + interface, the interface name can be given with a period: + + ``` + `enum`="`iface`.`enum-cname-suffix`" + ``` + + > [!NOTE] + > This attribute alone does not automatically restrict the legal values for + > this argument. If values from outside of the enumeration need to be + > forbidden, that must be specified explicitly in the documentation. + > + > A common design pattern is to have the server advertise the supported + > enumeration or bit values with events and explicitly forbid clients from + > using any other values in requests. This also requires a protocol error + > code to be specified with the error enum to be raised if a client uses an + > illegal value, see [interface](#interface). + +### enum + +Parent elements: protocol + +``` +enum ::= (description?, entry*) +``` + +This tag defines an enumeration of integer values. Enumerations are merely a +syntactic construct to give names to arbitrary integer constants. Each constant +is listed as an entry with its name. There are two types of enumerations: +regular enumerations and bitfields. + +Regular enumerations do not use `bitfield` attribute, or they set it to +`"false"`. The set of pre-defined values that belong to a regular enumeration is +exactly the set of values listed as entry elements after the protocol object +version is taken into account. See the entry attributes `since` and +`deprecated-since`. + +Bitfields set `bitfield` to `"true"`. The set of values that belong to a +bitfield enumeration are all the values that can be formed by the bitwise-or +operator from the set of values listed as entry elements like in the regular +enumeration. Usually also zero is implicitly included. + +All the values in a regular enumeration must be either signed or unsigned 32-bit +integers. All the values in a bitfield enumeration must be unsigned 32-bit +integers. + +**Required attributes** + +`name`="`cname-suffix`" + : The name of the enumeration. cname-suffix-requirements The name must be + unique within all enumerations in the containing interface. The name is used + as the namespace for all the contained entry elements. + +**Optional attributes** + +`since`="`S`" + : `S` must be an integer greater than zero. If `since` is not specified, + `since="1"` is assumed. + + This enumeration was added in interface `version` `S`. The enumeration does + not exist if the protocol object has a bound version smaller than `S`. + +`bitfield`="`true`" | "`false`" + : Specifies if this enumeration is a bitfield. Defaults to `"false"`. + +### entry + +Parent elements: enum + +``` +entry ::= description? +``` + +Defines a name for an integer constant and makes it part of the set of values of +the containing enumeration. + +**Required attributes** + +`name`="`cname-suffix`" + : The name of a value in an enumeration. cname-suffix-requirements The name + must be unique within all entry elements in the containing enum. + +`value`="`V`" + : An integer value. The value can be given in decimal, hexadecimal, or octal + representation. + +**Optional attributes** + +`summary`="`summary`" + : A short (half a line at most) description. This attribute should not be used + if a description is used. + +`since`="`S`" + : `S` must be an integer greater than zero. If `since` is not specified, + `since="1"` is assumed. + + This value was added in interface `version` `S`. + +`deprecated-since`="`D`" + : `D` must be an integer greater than the value of `since`. If + `deprecated-since` is not specified, then the value is not deprecated in any + version of the containing interface. + + This value was removed in interface `version` `D`. This does not make the + value automatically illegal to use, see [arg](#arg) attribute `enum`. diff --git a/doc/book/src/Protocol.md b/doc/book/src/Protocol.md new file mode 100644 index 00000000..f195707e --- /dev/null +++ b/doc/book/src/Protocol.md @@ -0,0 +1,371 @@ +# Wayland Protocol and Model of Operation + +## Basic Principles + +The Wayland protocol is an asynchronous object oriented protocol. All requests +are method invocations on some object. The requests include an object ID that +uniquely identifies an object on the server. Each object implements an interface +and the requests include an opcode that identifies which method in the interface +to invoke. + +The protocol is message-based. A message sent by a client to the server is +called request. A message from the server to a client is called event. A message +has a number of arguments, each of which has a certain type (see [Wire +Format](#wire-format) for a list of argument types). + +Additionally, the protocol can specify `enum`s which associate names to specific +numeric enumeration values. These are primarily just descriptive in nature: at +the wire format level enums are just integers. But they also serve a secondary +purpose to enhance type safety or otherwise add context for use in language +bindings or other such code. This latter usage is only supported so long as code +written before these attributes were introduced still works after; in other +words, adding an enum should not break API, otherwise it puts backwards +compatibility at risk. + +`enum`s can be defined as just a set of integers, or as bitfields. This is +specified via the `bitfield` boolean attribute in the `enum` definition. If this +attribute is true, the enum is intended to be accessed primarily using bitwise +operations, for example when arbitrarily many choices of the enum can be ORed +together; if it is false, or the attribute is omitted, then the enum arguments +are a just a sequence of numerical values. + +The `enum` attribute can be used on either `uint` or `int` arguments, however if +the `enum` is defined as a `bitfield`, it can only be used on `uint` args. + +The server sends back events to the client, each event is emitted from an +object. Events can be error conditions. The event includes the object ID and the +event opcode, from which the client can determine the type of event. Events are +generated both in response to requests (in which case the request and the event +constitutes a round trip) or spontaneously when the server state changes. + +- State is broadcast on connect, events are sent out when state changes. Clients + must listen for these changes and cache the state. There is no need (or + mechanism) to query server state. + +- The server will broadcast the presence of a number of global objects, which in + turn will broadcast their current state. + +## Code Generation + +The interfaces, requests and events are defined in +[protocol/wayland.xml](https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/protocol/wayland.xml). +This xml is used to generate the function prototypes that can be used by clients +and compositors. + +The protocol entry points are generated as inline functions which just wrap the +`wl_proxy_*` functions. The inline functions aren't part of the library ABI and +language bindings should generate their own stubs for the protocol entry points +from the xml. + +## Wire Format + +The protocol is sent over a UNIX domain stream socket, where the endpoint +usually is named `wayland-0` (although it can be changed via _WAYLAND_DISPLAY_ +in the environment). Beginning in Wayland 1.15, implementations can optionally +support server socket endpoints located at arbitrary locations in the filesystem +by setting _WAYLAND_DISPLAY_ to the absolute path at which the server endpoint +listens. The socket may also be provided through file descriptor inheritance, in +which case _WAYLAND_SOCKET_ is set. + +Every message is structured as 32-bit words; values are represented in the +host's byte-order. The message header has 2 words in it: + +- The first word is the sender's object ID (32-bit). + +- The second has 2 parts of 16-bit. The upper 16-bits are the message size in + bytes, starting at the header (i.e. it has a minimum value of 8).The lower is + the request/event opcode. + +The payload describes the request/event arguments. Every argument is always +aligned to 32-bits. Where padding is required, the value of padding bytes is +undefined. There is no prefix that describes the type, but it is inferred +implicitly from the xml specification. + +The representation of argument types are as follows: + +int +uint + : The value is the 32-bit value of the signed/unsigned int. + +fixed + : Signed 24.8 decimal numbers. It is a signed decimal type which offers a sign + bit, 23 bits of integer precision and 8 bits of decimal precision. This is + exposed as an opaque struct with conversion helpers to and from double and + int on the C API side. + +string + : Starts with an unsigned 32-bit length (including null terminator), followed + by the UTF-8 encoded string contents, including terminating null byte, then + padding to a 32-bit boundary. A null value is represented with a length of + 0. Interior null bytes are not permitted. + +object + : 32-bit object ID. A null value is represented with an ID of 0. + +new_id + : The 32-bit object ID. Generally, the interface used for the new object is + inferred from the xml, but in the case where it's not specified, a new_id is + preceded by a `string` specifying the interface name, and a `uint` + specifying the version. + +array + : Starts with 32-bit array size in bytes, followed by the array contents + verbatim, and finally padding to a 32-bit boundary. + +fd + : The file descriptor is not stored in the message buffer, but in the + ancillary data of the UNIX domain socket message (msg_control). + +The protocol does not specify the exact position of the ancillary data in the +stream, except that the order of file descriptors is the same as the order of +messages and `fd` arguments within messages on the wire. + +In particular, it means that any byte of the stream, even the message header, +may carry the ancillary data with file descriptors. + +Clients and compositors should queue incoming data until they have whole +messages to process, as file descriptors may arrive earlier or later than the +corresponding data bytes. + +## Versioning + +Every interface is versioned and every protocol object implements a particular +version of its interface. For global objects, the maximum version supported by +the server is advertised with the global and the actual version of the created +protocol object is determined by the version argument passed to +wl_registry.bind(). For objects that are not globals, their version is inferred +from the object that created them. + +In order to keep things sane, this has a few implications for interface +versions: + +- The object creation hierarchy must be a tree. Otherwise, inferring object + versions from the parent object becomes a much more difficult to properly + track. + +- When the version of an interface increases, so does the version of its parent + (recursively until you get to a global interface) + +- A global interface's version number acts like a counter for all of its child + interfaces. Whenever a child interface gets modified, the global parent's + interface version number also increases (see above). The child interface then + takes on the same version number as the new version of its parent global + interface. + +To illustrate the above, consider the wl_compositor interface. It has two +children, wl_surface and wl_region. As of wayland version 1.2, wl_surface and +wl_compositor are both at version 3. If something is added to the wl_region +interface, both wl_region and wl_compositor will get bumpped to version 4. If, +afterwards, wl_surface is changed, both wl_compositor and wl_surface will be at +version 5. In this way the global interface version is used as a sort of +"counter" for all of its child interfaces. This makes it very simple to know the +version of the child given the version of its parent. The child is at the +highest possible interface version that is less than or equal to its parent's +version. + +It is worth noting a particular exception to the above versioning scheme. The +wl_display (and, by extension, wl_registry) interface cannot change because it +is the core protocol object and its version is never advertised nor is there a +mechanism to request a different version. + +## Connect Time + +There is no fixed connection setup information, the server emits multiple events +at connect time, to indicate the presence and properties of global objects: +outputs, compositor, input devices. + +## Security and Authentication + +- mostly about access to underlying buffers, need new drm auth mechanism (the + grant-to ioctl idea), need to check the cmd stream? + +- getting the server socket depends on the compositor type, could be a system + wide name, through fd passing on the session dbus. or the client is forked by + the compositor and the fd is already opened. + +## Creating Objects + +Each object has a unique ID. The IDs are allocated by the entity creating the +object (either client or server). IDs allocated by the client are in the range +[1, 0xfeffffff] while IDs allocated by the server are in the range [0xff000000, +0xffffffff]. The 0 ID is reserved to represent a null or non-existent object. +For efficiency purposes, the IDs are densely packed in the sense that the ID N +will not be used until N-1 has been used. This ordering is not merely a +guideline, but a strict requirement, and there are implementations of the +protocol that rigorously enforce this rule, including the ubiquitous libwayland. + +## Compositor + +The compositor is a global object, advertised at connect time. + +See [wl_compositor](https://wayland.app/protocols/wayland#wl_compositor) for the +protocol description. + +## Surfaces + +A surface manages a rectangular grid of pixels that clients create for +displaying their content to the screen. Clients don't know the global position +of their surfaces, and cannot access other clients' surfaces. + +Once the client has finished writing pixels, it 'commits' the buffer; this +permits the compositor to access the buffer and read the pixels. When the +compositor is finished, it releases the buffer back to the client. + +See [wl_surface](https://wayland.app/protocols/wayland#wl_surface) for the +protocol description. + +## Input + +A seat represents a group of input devices including mice, keyboards and +touchscreens. It has a keyboard and pointer focus. Seats are global objects. +Pointer events are delivered in surface-local coordinates. + +The compositor maintains an implicit grab when a button is pressed, to ensure +that the corresponding button release event gets delivered to the same surface. +But there is no way for clients to take an explicit grab. Instead, surfaces can +be mapped as 'popup', which combines transient window semantics with a pointer +grab. + +To avoid race conditions, input events that are likely to trigger further +requests (such as button presses, key events, pointer motions) carry serial +numbers, and requests such as wl_surface.set_popup require that the serial +number of the triggering event is specified. The server maintains a +monotonically increasing counter for these serial numbers. + +Input events also carry timestamps with millisecond granularity. Their base is +undefined, so they can't be compared against system time (as obtained with +clock_gettime or gettimeofday). They can be compared with each other though, and +for instance be used to identify sequences of button presses as double or triple +clicks. + +See [wl_seat](https://wayland.app/protocols/wayland#wl_seat) for the protocol +description. + +Talk about: + +- keyboard map, change events + +- xkb on Wayland + +- multi pointer Wayland + +A surface can change the pointer image when the surface is the pointer focus of +the input device. Wayland doesn't automatically change the pointer image when a +pointer enters a surface, but expects the application to set the cursor it wants +in response to the pointer focus and motion events. The rationale is that a +client has to manage changing pointer images for UI elements within the surface +in response to motion events anyway, so we'll make that the only mechanism for +setting or changing the pointer image. If the server receives a request to set +the pointer image after the surface loses pointer focus, the request is ignored. +To the client this will look like it successfully set the pointer image. + +Setting the pointer image to NULL causes the cursor to be hidden. + +The compositor will revert the pointer image back to a default image when no +surface has the pointer focus for that device. + +What if the pointer moves from one window which has set a special pointer image +to a surface that doesn't set an image in response to the motion event? The new +surface will be stuck with the special pointer image. We can't just revert the +pointer image on leaving a surface, since if we immediately enter a surface that +sets a different image, the image will flicker. If a client does not set a +pointer image when the pointer enters a surface, the pointer stays with the +image set by the last surface that changed it, possibly even hidden. Such a +client is likely just broken. + +## Output + +An output is a global object, advertised at connect time or as it comes and +goes. + +See [wl_output](https://wayland.app/protocols/wayland#wl_output) for the +protocol description. + +- laid out in a big (compositor) coordinate system + +- basically xrandr over Wayland + +- geometry needs position in compositor coordinate system + +- events to advertise available modes, requests to move and change modes + +## Data sharing between clients + +The Wayland protocol provides clients a mechanism for sharing data that allows +the implementation of copy-paste and drag-and-drop. The client providing the +data creates a `wl_data_source` object and the clients obtaining the data will +see it as `wl_data_offer` object. This interface allows the clients to agree on +a mutually supported mime type and transfer the data via a file descriptor that +is passed through the protocol. + +The next section explains the negotiation between data source and data offer +objects. [Data devices](#data-devices) explains how these objects are created +and passed to different clients using the `wl_data_device` interface that +implements copy-paste and drag-and-drop support. + +See [wl_data_offer](https://wayland.app/protocols/wayland#wl_data_offer), +[wl_data_source](https://wayland.app/protocols/wayland#wl_data_source), +[wl_data_device](https://wayland.app/protocols/wayland#wl_data_device) and +[wl_data_device_manager](https://wayland.app/protocols/wayland#wl_data_device_manager) +for protocol descriptions. + +MIME is defined in RFC's 2045-2049. A [registry of MIME +types](https://www.iana.org/assignments/media-types/media-types.xhtml) is +maintained by the Internet Assigned Numbers Authority (IANA). + +### Data negotiation + +A client providing data to other clients will create a `wl_data_source` object +and advertise the mime types for the formats it supports for that data through +the `wl_data_source.offer` request. On the receiving end, the data offer object +will generate one `wl_data_offer.offer` event for each supported mime type. + +The actual data transfer happens when the receiving client sends a +`wl_data_offer.receive` request. This request takes a mime type and a file +descriptor as arguments. This request will generate a `wl_data_source.send` +event on the sending client with the same arguments, and the latter client is +expected to write its data to the given file descriptor using the chosen mime +type. + +### Data devices + +Data devices glue data sources and offers together. A data device is associated +with a `wl_seat` and is obtained by the clients using the +`wl_data_device_manager` factory object, which is also responsible for creating +data sources. + +Clients are informed of new data offers through the `wl_data_device.data_offer` +event. After this event is generated the data offer will advertise the available +mime types. New data offers are introduced prior to their use for copy-paste or +drag-and-drop. + +#### Selection + +Each data device has a selection data source. Clients create a data source +object using the device manager and may set it as the current selection for a +given data device. Whenever the current selection changes, the client with +keyboard focus receives a `wl_data_device.selection` event. This event is also +generated on a client immediately before it receives keyboard focus. + +The data offer is introduced with `wl_data_device.data_offer` event before the +selection event. + +#### Drag and Drop + +A drag-and-drop operation is started using the `wl_data_device.start_drag` +request. This requests causes a pointer grab that will generate enter, motion +and leave events on the data device. A data source is supplied as argument to +start_drag, and data offers associated with it are supplied to clients surfaces +under the pointer in the `wl_data_device.enter` event. The data offer is +introduced to the client prior to the enter event with the +`wl_data_device.data_offer` event. + +Clients are expected to provide feedback to the data sending client by calling +the `wl_data_offer.accept` request with a mime type it accepts. If none of the +advertised mime types is supported by the receiving client, it should supply +NULL to the accept request. The accept request causes the sending client to +receive a `wl_data_source.target` event with the chosen mime type. + +When the drag ends, the receiving client receives a `wl_data_device.drop` event +at which it is expected to transfer the data using the `wl_data_offer.receive` +request. diff --git a/doc/book/src/SUMMARY.md b/doc/book/src/SUMMARY.md new file mode 100644 index 00000000..713b4e02 --- /dev/null +++ b/doc/book/src/SUMMARY.md @@ -0,0 +1,12 @@ +# Summary + +[Foreword](Foreword.md) + +- [Introduction](./Introduction.md) +- [Types of Compositors](./Compositors.md) +- [Wayland Architecture](./Architecture.md) +- [Wayland Protocol and Model of Operation](./Protocol.md) +- [Message Definition Language](./Message_XML.md) +- [X11 Application Support](./Xwayland.md) +- [Content Updates](./Content_Updates.md) +- [Color management](./Color.md) diff --git a/doc/book/src/Xwayland.md b/doc/book/src/Xwayland.md new file mode 100644 index 00000000..dd7f9f77 --- /dev/null +++ b/doc/book/src/Xwayland.md @@ -0,0 +1,120 @@ +# X11 Application Support + +## Introduction + +Being able to run existing X11 applications is crucial for the adoption of +Wayland, especially on desktops, as there will always be X11 applications that +have not been or cannot be converted into Wayland applications, and throwing +them all away would be prohibitive. Therefore a Wayland compositor often needs +to support running X11 applications. + +X11 and Wayland are different enough that there is no "simple" way to translate +between them. Most of X11 is uninteresting to a Wayland compositor. That, +combined with the gigantic implementation effort needed to support X11, makes it +intractable to just write X11 support directly in a Wayland compositor. The +implementation would be nothing short of a real X11 server. + +Therefore, Wayland compositors should use Xwayland, the X11 server that lives in +the Xorg server source code repository and shares most of the implementation +with the Xorg server. Xwayland is a complete X11 server, just like Xorg is, but +instead of driving the displays and opening input devices, it acts as a Wayland +client. The rest of this chapter talks about how Xwayland works. + +For integration and architecture reasons, while Xwayland is a Wayland client of +the Wayland compositor, the Wayland compositor is an X11 client of Xwayland. +This circular dependency requires special care from the Wayland compositor. + +## Two Modes for Foreign Windows + +In general, windows from a foreign window system can be presented in one of two +ways: rootless and rootful (not rootless). + +In rootful mode, the foreign window system as a whole is represented as a window +(or more) of its own. You have a native window, inside which all the foreign +windows are. The advantage of this approach in Xwayland's case is that you can +run your favourite X11 window manager to manage your X11 applications. The +disadvantage is that the foreign windows do not integrate with the native +desktop. Therefore this mode is not usually used. + +In rootless mode, each foreign window is a first-class resident among the native +windows. Foreign windows are not confined inside a native window but act as if +they were native windows. The advantage is that one can freely stack and mix +native and foreign windows, which is not possible in rootful mode. The +disadvantage is that this mode is harder to implement and fundamental +differences in window systems may prevent some things from working. With +rootless Xwayland, the Wayland compositor must take the role as the X11 window +manager, and one cannot use any other X11 window manager in its place. + +This chapter concentrates on the rootless mode, and ignores the rootful mode. + +## Architecture + +A Wayland compositor usually takes care of launching Xwayland. Xwayland works in +cooperation with a Wayland compositor as follows: + +**Xwayland architecture diagram** + +![](images/xwayland-architecture.png) + +An X11 application connects to Xwayland just like it would connect to any X +server. Xwayland processes all the X11 requests. On the other end, Xwayland is a +Wayland client that connects to the Wayland compositor. + +The X11 window manager (XWM) is an integral part of the Wayland compositor. XWM +uses the usual X11 window management protocol to manage all X11 windows in +Xwayland. Most importantly, XWM acts as a bridge between Xwayland window state +and the Wayland compositor's window manager (WWM). This way WWM can manage all +windows, both native Wayland and X11 (Xwayland) windows. This is very important +for a coherent user experience. + +Since Xwayland uses Wayland for input and output, it does not have any use for +the device drivers that Xorg uses. None of the xf86-video-* or xf86-input-* +modules are used. There also is no configuration file for the Xwayland server. +For optional hardware accelerated rendering, Xwayland uses GLAMOR. + +A Wayland compositor usually spawns only one Xwayland instance. This is because +many X11 applications assume they can communicate with other X11 applications +through the X server, and this requires a shared X server instance. This also +means that Xwayland does not protect nor isolate X11 clients from each other, +unless the Wayland compositor specifically chooses to break the X11 client +intercommunications by spawning application specific Xwayland instances. X11 +clients are naturally isolated from Wayland clients. + +Xwayland compatibility compared to a native X server will probably never reach +100%. Desktop environment (DE) components, specifically X11 window managers, are +practically never supported. An X11 window manager would not know about native +Wayland windows, so it could manage only X11 windows. On the other hand, there +must be an XWM that reserves the exclusive window manager role so that the +Wayland compositor could show the X11 windows appropriately. For other DE +components, like pagers and panels, adding the necessary interfaces to support +them in WWM through XWM is often considered not worthwhile. + +## X Window Manager (XWM) + +From the X11 point of view, the X window manager (XWM) living inside a Wayland +compositor is just like any other window manager. The difference is mostly in +which process it resides in, and the few extra conventions in the X11 protocol +to support Wayland window management (WWM) specifically. + +There are two separate asynchronous communication channels between Xwayland and +a Wayland compositor: one uses the Wayland protocol, and the other one, solely +for XWM, uses X11 protocol. This setting demands great care from the XWM +implementation to avoid (random) deadlocks with Xwayland. It is often nearly +impossible to prove that synchronous or blocking X11 calls from XWM cannot cause +a deadlock, and therefore it is strongly recommended to make all X11 +communications asynchronous. All Wayland communications are already asynchronous +by design. + +### Window identification + +In Xwayland, an X11 window may have a corresponding wl_surface object in +Wayland. The wl_surface object is used for input and output: it is referenced by +input events and used to provide the X11 window content to the Wayland +compositor. The X11 window and the wl_surface live in different protocol +streams, and they need to be matched for XWM to do its job. + +When Xwayland creates a wl_surface on Wayland, it will also send an X11 +ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying the +wl_surface Wayland object ID as the first 32-bit data element. This is how XWM +can associate a wl_surface with an X11 window. Note that the request to create a +wl_surface and the ID message may arrive in any order in the Wayland compositor. From 131b8d0dd0158910f845e2f50e32013fdf35b09d Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 30 Jan 2026 21:06:40 +0100 Subject: [PATCH 1121/1152] doc: remove docbook -> mdbook conversion tool Signed-off-by: Julian Orth --- docbook-to-mdbook/.gitignore | 1 - docbook-to-mdbook/Cargo.lock | 184 ------- docbook-to-mdbook/Cargo.toml | 12 - docbook-to-mdbook/rustfmt.toml | 1 - docbook-to-mdbook/src/main.rs | 935 --------------------------------- 5 files changed, 1133 deletions(-) delete mode 100644 docbook-to-mdbook/.gitignore delete mode 100644 docbook-to-mdbook/Cargo.lock delete mode 100644 docbook-to-mdbook/Cargo.toml delete mode 100644 docbook-to-mdbook/rustfmt.toml delete mode 100644 docbook-to-mdbook/src/main.rs diff --git a/docbook-to-mdbook/.gitignore b/docbook-to-mdbook/.gitignore deleted file mode 100644 index ea8c4bf7..00000000 --- a/docbook-to-mdbook/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/docbook-to-mdbook/Cargo.lock b/docbook-to-mdbook/Cargo.lock deleted file mode 100644 index 507516d9..00000000 --- a/docbook-to-mdbook/Cargo.lock +++ /dev/null @@ -1,184 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "docbook-to-mdbook" -version = "0.1.0" -dependencies = [ - "anyhow", - "bstr", - "isnt", - "quick-xml", - "regex", - "textwrap", -] - -[[package]] -name = "isnt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1697e6b71679da96d5c41bb9035116141baadbf59a60625fd66cb3c9584e7b0" - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-xml" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "syn" -version = "2.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" diff --git a/docbook-to-mdbook/Cargo.toml b/docbook-to-mdbook/Cargo.toml deleted file mode 100644 index 508f379d..00000000 --- a/docbook-to-mdbook/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "docbook-to-mdbook" -version = "0.1.0" -edition = "2024" - -[dependencies] -quick-xml = "0.39.0" -anyhow = "1.0.100" -bstr = "1.12.1" -textwrap = "0.16.2" -regex = "1.12.2" -isnt = "0.2.0" diff --git a/docbook-to-mdbook/rustfmt.toml b/docbook-to-mdbook/rustfmt.toml deleted file mode 100644 index 58b51174..00000000 --- a/docbook-to-mdbook/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -imports_granularity = "One" diff --git a/docbook-to-mdbook/src/main.rs b/docbook-to-mdbook/src/main.rs deleted file mode 100644 index 3ebc5493..00000000 --- a/docbook-to-mdbook/src/main.rs +++ /dev/null @@ -1,935 +0,0 @@ -#![expect(clippy::single_char_add_str)] - -use { - anyhow::{Context, bail}, - bstr::ByteSlice, - isnt::std_1::primitive::IsntStrExt, - quick_xml::{ - Reader, - events::{BytesStart, Event}, - }, - regex::Regex, - std::{ - borrow::Cow, - fs::{File, read_dir}, - io::{BufWriter, Write}, - mem, - path::Path, - sync::LazyLock, - }, - textwrap::{Options, WordSeparator, WordSplitter, WrapAlgorithm}, -}; - -const XML_ROOT: &str = "../doc/publican"; -const MD_ROOT: &str = "../doc/book"; - -fn main() -> anyhow::Result<()> { - for file in read_dir(XML_ROOT).context("open publican")? { - let file = file.unwrap(); - let path = file.path(); - let Some(name) = path.file_name() else { - continue; - }; - let name = name.to_str().unwrap(); - if !name.ends_with(".xml") { - continue; - } - match name { - "Architecture.xml" - | "Color.xml" - | "Compositors.xml" - | "Content_Updates.xml" - | "Introduction.xml" - | "Message_XML.xml" - | "Protocol.xml" - | "Foreword.xml" - | "Xwayland.xml" => handle_chapter_file(name) - .with_context(|| format!("handle_chapter_file {}", name))?, - "Book_Info.xml" | "Wayland.xml" | "Author_Group.xml" | "Client.xml" | "Server.xml" => { - continue; - } - _ => bail!("unknown file name {name}"), - } - } - handle_wayland_xml().context("Wayland.xml")?; - Ok(()) -} - -fn handle_wayland_xml() -> anyhow::Result<()> { - let input = Path::new(XML_ROOT).join("Wayland.xml"); - let input = std::fs::read_to_string(input).context("read xml")?; - let mut r = Reader::from_str(&input); - let output = Path::new(MD_ROOT).join("src").join("SUMMARY.md"); - let mut w = BufWriter::new(File::create(output).context("open md")?); - writeln!(w, "# Summary")?; - writeln!(w)?; - writeln!(w, "[Foreword](Foreword.md)")?; - writeln!(w)?; - loop { - let event = r.read_event().context("read event")?; - match event { - Event::Start(c) => match c.name().as_ref() { - b"book" => loop { - let event = r.read_event().context("read event")?; - match event { - Event::Empty(e) if e.name().as_ref() == b"xi:include" => { - let href = e - .try_get_attribute("href") - .context("href")? - .context("href")? - .unescape_value() - .context("href")?; - let name = match &*href { - "Book_Info.xml" => continue, - "Foreword.xml" => continue, - "Introduction.xml" => "Introduction", - "Compositors.xml" => "Types of Compositors", - "Architecture.xml" => "Wayland Architecture", - "Protocol.xml" => "Wayland Protocol and Model of Operation", - "Message_XML.xml" => "Message Definition Language", - "Xwayland.xml" => "X11 Application Support", - "Content_Updates.xml" => "Content Updates", - "Color.xml" => "Color management", - "ProtocolSpec.xml" => continue, - "Client.xml" => continue, - "Server.xml" => continue, - _ => bail!("unexpected link {href}"), - }; - writeln!(w, "- [{name}](./{})", href.replace(".xml", ".md"))?; - } - Event::Text(t) if t.trim().is_empty() => {} - Event::End(e) if e.name().as_ref() == b"book" => break, - _ => bail!("unexpected event {event:?}"), - } - }, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::Decl(_) => {} - Event::DocType(_) => {} - Event::Text(t) if t.trim().is_empty() => {} - Event::Eof => break, - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) -} - -fn handle_chapter_file(name: &str) -> anyhow::Result<()> { - let input = Path::new(XML_ROOT).join(name); - let input = std::fs::read_to_string(input).context("read xml")?; - let mut reader = Reader::from_str(&input); - let output = Path::new(MD_ROOT) - .join("src") - .join(name) - .with_extension("md"); - let mut output = BufWriter::new(File::create(output).context("open md")?); - Handler { - w: &mut output, - r: &mut reader, - text: Default::default(), - need_newline: false, - last_line_has_content: false, - have_indent_1: Default::default(), - indent_1: Default::default(), - indent_2: Default::default(), - } - .handle_chapter_file() -} - -struct Handler<'a, 'b, W> { - w: &'a mut W, - r: &'a mut Reader<&'b [u8]>, - text: String, - need_newline: bool, - last_line_has_content: bool, - have_indent_1: bool, - indent_1: String, - indent_2: String, -} - -#[derive(Copy, Clone, Eq, PartialEq)] -enum TitleType { - Chapter, - Section(usize), - Bold, -} - -enum ListType { - Bullet, - Numbered(usize), - Itemized, -} - -static WHITESPACE: LazyLock = LazyLock::new(|| Regex::new(r#"[\n\t ]+"#).unwrap()); - -impl Handler<'_, '_, W> -where - W: Write, -{ - fn handle_chapter_file(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - match event { - Event::Start(c) => match c.name().as_ref() { - b"preface" | b"chapter" => self.handle_chapter().context("handle_chapter")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::Decl(_) => {} - Event::DocType(_) => {} - Event::Text(t) if t.trim().is_empty() => {} - Event::Eof => break, - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_chapter(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(s) => match s.name().as_ref() { - b"title" => self - .handle_title(TitleType::Chapter) - .context("handle_title")?, - b"literallayout" | b"para" => self.handle_para(false).context("handle_para")?, - b"section" => self.handle_section(0).context("handle_section")?, - _ => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::Empty(s) if s.name().as_ref() == b"xi:include" => {} - Event::End(e) if e.name().as_ref() == b"chapter" => break, - Event::End(e) if e.name().as_ref() == b"preface" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_title(&mut self, ty: TitleType) -> anyhow::Result<()> { - match ty { - TitleType::Chapter => self.text.push_str("# "), - TitleType::Section(depth) => { - self.text.push_str("##"); - for _ in 0..depth { - self.text.push_str("#"); - } - self.text.push_str(" "); - } - TitleType::Bold => self.text.push_str("**"), - } - let mut first = true; - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Text(v) => { - if first { - first = false; - } else { - self.text.push_str(" "); - } - self.text.push_str(v.decode().unwrap().trim()); - } - Event::End(v) if &*v == b"title" => break, - _ => bail!("unexpected event {event:?}"), - } - } - match ty { - TitleType::Chapter => {} - TitleType::Section(_) => {} - TitleType::Bold => self.text.push_str("**"), - } - let text = mem::take(&mut self.text); - self.write_line(&text)?; - self.text = text; - self.text.clear(); - self.need_newline = true; - Ok(()) - } - - fn handle_section(&mut self, depth: usize) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(s) => match s.name().as_ref() { - b"section" => self.handle_section(depth + 1).context("handle_section")?, - b"title" => self - .handle_title(TitleType::Section(depth)) - .context("handle_title")?, - b"synopsis" => self.handle_para(true).context("handle_synopsis")?, - b"para" => self.handle_para(false).context("handle_para")?, - b"orderedlist" => self.handle_orderedlist().context("handle_orderedlist")?, - b"itemizedlist" => self.handle_itemizedlist().context("handle_itemizedlist")?, - b"figure" => self.handle_figure().context("handle_figure")?, - b"variablelist" => self.handle_variablelist().context("handle_variablelist")?, - b"mediaobject" | b"mediaobjectco" => { - self.handle_mediaobject().context("handle_mediaobject")? - } - _ => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"section" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_xref(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { - let url = e - .try_get_attribute("linkend") - .context("linkend")? - .context("linkend")? - .unescape_value() - .context("linkend")?; - let name_buf; - let url_buf; - let (name, url) = if let Some(v) = url.strip_prefix("sect-") - && let Some((sect, v)) = v.split_once("-") - { - match sect { - "Protocol" => match v { - "Wire-Format" => ("Wire Format", "#wire-format"), - "data-sharing-devices" => ("Data devices", "#data-devices"), - _ => bail!("unhandled protocol link {url}"), - }, - "MessageXML" => match v { - "tag-interface" => ("interface", "#interface"), - "tag-arg" => ("arg", "#arg"), - _ => bail!("unhandled message-xml link {url}"), - }, - _ => bail!("unhandled section {url}"), - } - } else if let Some(v) = url.strip_prefix("chap-") { - match v { - "Protocol" => ("Wayland Protocol and Model of Operation", "Protocol.md"), - _ => bail!("unhandled chap {url}"), - } - } else if let Some(v) = url.strip_prefix("protocol-spec-") { - if let Some((interface, v)) = v.split_once("-") - && let Some((ty, message)) = v.split_once("-") - { - name_buf = format!("{interface}.{message}"); - url_buf = - format!("https://wayland.app/protocols/wayland#{interface}:{ty}:{message}"); - } else { - name_buf = v.to_string(); - url_buf = format!("https://wayland.app/protocols/wayland#{v}"); - } - (&*name_buf, &*url_buf) - } else { - bail!("unknown link format {url}"); - }; - self.text.push_str("["); - self.text.push_str(name); - self.text.push_str("]"); - self.text.push_str("("); - self.text.push_str(url); - self.text.push_str(")"); - Ok(()) - } - - fn handle_filename(&mut self) -> anyhow::Result<()> { - let mut text = String::new(); - loop { - let event = self.r.read_event().context("read event")?; - match event { - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - text.push_str(&s); - } - Event::End(v) if &*v == b"filename" => break, - _ => bail!("unexpected event {event:?}"), - } - } - self.text.push_str("["); - self.text.push_str(text.trim()); - self.text.push_str("]"); - self.text - .push_str("(https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/"); - self.text.push_str(&text); - self.text.push_str(")"); - Ok(()) - } - - fn handle_link(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { - let mut text = String::new(); - loop { - let event = self.r.read_event().context("read event")?; - match event { - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - text.push_str(&s); - } - Event::End(v) if &*v == b"link" => break, - _ => bail!("unexpected event {event:?}"), - } - } - let url = e - .try_get_attribute("linkend") - .context("linkend")? - .context("linkend")? - .unescape_value() - .context("linkend")?; - let buf; - let url = if let Some(v) = url.strip_prefix("sect-") - && let Some((sect, v)) = v.split_once("-") - { - match sect { - "Compositors" => match v { - "System-Compositor" => "#system-compositor", - "Session-Compositor" => "#session-compositor", - _ => bail!("unhandled compositors link {url}"), - }, - "Library" => "https://gitlab.freedesktop.org/wayland/wayland", - _ => bail!("unhandled section {url}"), - } - } else if let Some(v) = url.strip_prefix("protocol-spec-") { - if let Some((interface, v)) = v.split_once("-") - && let Some((ty, message)) = v.split_once("-") - { - buf = format!("https://wayland.app/protocols/wayland#{interface}:{ty}:{message}"); - } else { - buf = format!("https://wayland.app/protocols/wayland#{v}"); - } - &buf - } else { - bail!("unknown link format {url}"); - }; - self.text.push_str("["); - self.text.push_str(text.trim()); - self.text.push_str("]"); - self.text.push_str("("); - self.text.push_str(url); - self.text.push_str(")"); - Ok(()) - } - - fn handle_ulink(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { - let mut text = String::new(); - loop { - let event = self.r.read_event().context("read event")?; - match event { - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - text.push_str(&s); - } - Event::End(v) if &*v == b"ulink" => break, - _ => bail!("unexpected event {event:?}"), - } - } - let url = e - .try_get_attribute("url") - .context("url")? - .context("url")? - .unescape_value() - .context("url")?; - self.text.push_str("["); - self.text.push_str(text.trim()); - self.text.push_str("]"); - self.text.push_str("("); - self.text.push_str(&url); - self.text.push_str(")"); - Ok(()) - } - - fn handle_code(&mut self) -> anyhow::Result<()> { - self.text.push_str("`"); - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - self.text.push_str(&s); - } - Event::End(v) if &*v == b"code" => break, - Event::End(v) if &*v == b"varname" => break, - Event::End(v) if &*v == b"literal" => break, - Event::End(v) if &*v == b"userinput" => break, - Event::End(v) if &*v == b"type" => break, - Event::End(v) if &*v == b"function" => break, - Event::End(v) if &*v == b"systemitem" => break, - _ => bail!("unexpected event {event:?}"), - } - } - self.text.push_str("`"); - Ok(()) - } - - fn handle_emphasis(&mut self) -> anyhow::Result<()> { - self.text.push_str("_"); - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - self.text.push_str(&s); - } - Event::End(v) if &*v == b"emphasis" => break, - Event::End(v) if &*v == b"firstterm" => break, - _ => bail!("unexpected event {event:?}"), - } - } - self.text.push_str("_"); - Ok(()) - } - - fn handle_newline(&mut self) -> anyhow::Result<()> { - if mem::take(&mut self.need_newline) { - self.write_line("")?; - } - Ok(()) - } - - fn write_line(&mut self, text: &str) -> anyhow::Result<()> { - self.handle_newline()?; - let text = text.trim_end(); - if text.is_empty() { - let indent = self.indent_1.trim_end(); - if indent.is_empty() { - if mem::take(&mut self.last_line_has_content) { - writeln!(self.w)?; - // dbg!(""); - } - } else { - writeln!(self.w, "{}", indent)?; - // dbg!("indent"); - self.last_line_has_content = true; - } - } else { - writeln!(self.w, "{}{text}", self.indent_1)?; - // dbg!(format!("{}{text}", self.indent_1)); - self.last_line_has_content = true; - } - self.clear_indent_1(); - Ok(()) - } - - fn clear_indent_1(&mut self) { - if self.have_indent_1 { - self.have_indent_1 = false; - self.indent_1.clone_from(&self.indent_2); - } - } - - fn push_indent( - &mut self, - indent: &str, - cont: bool, - f: impl FnOnce(&mut Self) -> anyhow::Result<()>, - ) -> anyhow::Result<()> { - self.handle_newline()?; - let len = self.indent_1.len(); - self.have_indent_1 = true; - self.indent_1.push_str(indent); - self.indent_1.push_str(" "); - if cont { - self.indent_2.push_str(indent); - self.indent_2.push_str(" "); - } else { - for _ in self.indent_2.len()..self.indent_1.len() { - self.indent_2.push_str(" "); - } - } - f(self)?; - self.indent_1.truncate(len); - self.indent_2.truncate(len); - Ok(()) - } - - fn flush_text(&mut self, synopsis: bool) -> anyhow::Result<()> { - const MAX_WIDTH: usize = 80; - self.handle_newline()?; - if synopsis { - self.write_line("```")?; - } - let text = mem::take(&mut self.text); - let trimmed = text.trim(); - if trimmed.is_not_empty() { - let options = Options::new(MAX_WIDTH) - .break_words(false) - .wrap_algorithm(WrapAlgorithm::FirstFit) - .word_separator(WordSeparator::AsciiSpace) - .word_splitter(WordSplitter::NoHyphenation) - .initial_indent(&self.indent_1) - .subsequent_indent(&self.indent_2); - let lines = textwrap::wrap(trimmed.trim(), options); - for line in lines { - writeln!(self.w, "{line}")?; - // dbg!(line); - self.last_line_has_content = true; - self.clear_indent_1(); - } - self.text = text; - } - if synopsis { - self.write_line("```")?; - } - self.text.clear(); - Ok(()) - } - - fn handle_admonition(&mut self, name: &str) -> anyhow::Result<()> { - self.push_indent(">", true, |slf| { - slf.write_line(&format!("[!{name}]"))?; - loop { - let event = slf.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(v) => match v.name().as_ref() { - b"simpara" | b"para" => slf.handle_para(false).context("handle_para")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::Text(t) if t.trim().is_empty() => {} - Event::End(v) if &*v == b"warning" => break, - Event::End(v) if &*v == b"note" => break, - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - }) - } - - fn handle_para(&mut self, synopsis: bool) -> anyhow::Result<()> { - self.handle_text_block(synopsis)?; - self.need_newline = true; - Ok(()) - } - - fn handle_text_block(&mut self, synopsis: bool) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(v) => match v.name().as_ref() { - b"synopsis" => { - self.flush_text(synopsis)?; - self.need_newline = true; - self.handle_para(true).context("handle_synopsis")? - } - b"emphasis" => self.handle_emphasis().context("handle_emphasis")?, - b"firstterm" => self.handle_emphasis().context("handle_firstterm")?, - b"type" => self.handle_code().context("handle_type")?, - b"code" => self.handle_code().context("handle_code")?, - b"systemitem" => self.handle_code().context("handle_systemitem")?, - b"function" => self.handle_code().context("handle_function")?, - b"filename" => self.handle_filename().context("handle_filename")?, - b"literal" => self.handle_code().context("handle_literal")?, - b"varname" => self.handle_code().context("handle_varname")?, - b"userinput" => self.handle_code().context("handle_userinput")?, - b"ulink" => self.handle_ulink(v).context("handle_ulink")?, - b"link" => self.handle_link(v).context("handle_link")?, - b"itemizedlist" => { - self.flush_text(synopsis)?; - self.need_newline = true; - self.handle_itemizedlist().context("handle_itemizedlist")? - } - b"orderedlist" => { - self.flush_text(synopsis)?; - self.need_newline = true; - self.handle_orderedlist().context("handle_orderedlist")? - } - b"variablelist" => { - self.flush_text(synopsis)?; - self.need_newline = true; - self.handle_variablelist().context("handle_variablelist")? - } - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::Empty(v) => match v.name().as_ref() { - b"xref" => self.handle_xref(v).context("handle_xref")?, - e => bail!("unexpected empty {:?}", e.as_bstr()), - }, - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - self.text.push_str(&s); - } - Event::GeneralRef(v) => { - self.text.push_str(&v.decode().unwrap()); - } - Event::End(v) if &*v == b"para" => break, - Event::End(v) if &*v == b"synopsis" => break, - Event::End(v) if &*v == b"simpara" => break, - Event::End(v) if &*v == b"literallayout" => break, - _ => bail!("unexpected event {event:?}"), - } - } - self.flush_text(synopsis)?; - Ok(()) - } - - fn handle_variablelist(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"title" => self.handle_title(TitleType::Bold).context("handle_title")?, - b"varlistentry" => self.handle_varlistentry().context("handle_varlistentry")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"variablelist" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_varlistentry(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"term" => self.handle_term().context("handle_term")?, - b"listitem" => self - .handle_listitem(ListType::Itemized) - .context("handle_listitem")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"varlistentry" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_term(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"literal" => self.handle_code().context("handle_literal")?, - b"synopsis" => self.handle_text_block(false).context("handle_synopsis")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"term" => break, - Event::Text(t) => { - let s = t.decode().unwrap(); - let s = WHITESPACE.replace_all(&s, " "); - self.text.push_str(&s); - } - _ => bail!("unexpected event {event:?}"), - } - } - self.flush_text(false)?; - Ok(()) - } - - fn handle_orderedlist(&mut self) -> anyhow::Result<()> { - let mut n = 1..; - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"listitem" => self - .handle_listitem(ListType::Numbered(n.next().unwrap())) - .context("handle_listitem")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"orderedlist" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_itemizedlist(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"listitem" => self - .handle_listitem(ListType::Bullet) - .context("handle_listitem")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"itemizedlist" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_listitem(&mut self, ty: ListType) -> anyhow::Result<()> { - let indent = match ty { - ListType::Bullet => Cow::Borrowed("-"), - ListType::Numbered(n) => Cow::Owned(format!("{n}.")), - ListType::Itemized => Cow::Borrowed(" :"), - }; - self.push_indent(&indent, false, |slf| { - loop { - let event = slf.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"simpara" | b"para" => slf.handle_para(false).context("handle_para")?, - b"warning" => slf.handle_admonition("WARNING").context("handle_warning")?, - b"note" => slf.handle_admonition("NOTE").context("handle_note")?, - b"variablelist" => { - slf.handle_variablelist().context("handle_variablelist")? - } - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"listitem" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - }) - } - - fn handle_figure(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"title" => self.handle_title(TitleType::Bold).context("handle_title")?, - b"mediaobject" | b"mediaobjectco" => { - self.handle_mediaobject().context("handle_mediaobject")? - } - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"figure" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_mediaobject(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"textobject" => self.handle_textobject().context("handle_textobject")?, - b"imageobject" => self.handle_imageobject().context("handle_imageobject")?, - b"imageobjectco" => self - .handle_imageobjectco() - .context("handle_imageobjectco")?, - b"caption" => self.handle_caption().context("handle_caption")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"mediaobject" => break, - Event::End(v) if &*v == b"mediaobjectco" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_textobject(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::End(v) if &*v == b"textobject" => break, - _ => {} - } - } - Ok(()) - } - - fn handle_imageobject(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"areaspec" => self.handle_areaspec().context("handle_areaspec")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::Empty(e) => match e.name().as_ref() { - b"imagedata" => self.handle_imagedata(e).context("handle_imagedata")?, - s => bail!("unexpected empty {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"imageobject" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_imageobjectco(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"areaspec" => self.handle_areaspec().context("handle_areaspec")?, - b"imageobject" => self.handle_imageobject().context("handle_imageobject")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"imageobjectco" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } - - fn handle_areaspec(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::End(v) if &*v == b"areaspec" => break, - _ => {} - } - } - Ok(()) - } - - fn handle_imagedata(&mut self, e: BytesStart<'_>) -> anyhow::Result<()> { - let fileref = e - .try_get_attribute("fileref") - .context("fileref")? - .context("fileref")? - .unescape_value() - .unwrap(); - self.write_line(&format!("![]({fileref})"))?; - self.need_newline = true; - Ok(()) - } - - fn handle_caption(&mut self) -> anyhow::Result<()> { - loop { - let event = self.r.read_event().context("read event")?; - // dbg!(&event); - match event { - Event::Start(e) => match e.name().as_ref() { - b"para" => self.handle_para(false).context("handle_para")?, - s => bail!("unexpected start {:?}", s.as_bstr()), - }, - Event::End(v) if &*v == b"caption" => break, - Event::Text(t) if t.trim().is_empty() => {} - _ => bail!("unexpected event {event:?}"), - } - } - Ok(()) - } -} From df7f2fb9e8f861c28b918d82af9f8416267d6bb3 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 30 Jan 2026 21:08:43 +0100 Subject: [PATCH 1122/1152] doc: add copyright notice to mdbook Signed-off-by: Julian Orth --- doc/book/src/Foreword.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/book/src/Foreword.md b/doc/book/src/Foreword.md index 48cadf6e..468b1654 100644 --- a/doc/book/src/Foreword.md +++ b/doc/book/src/Foreword.md @@ -9,3 +9,26 @@ There have been many contributors to this document and since this is only the first edition many errors are expected to be found. We appreciate corrections. Yours, the Wayland open-source community November 2012 + +## Copyright + +Copyright © 2012 Kristian Høgsberg + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From 4bddeba2154b00f4302adc1365f2c6d9bfaecfb9 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 30 Jan 2026 21:18:11 +0100 Subject: [PATCH 1123/1152] doc: copy images to mdbook Signed-off-by: Julian Orth --- .../content-updates/content-updates.drawio | 1528 +++++++++++++++++ .../simple-desynchronized.drawio | 198 +++ .../simple-synchronized.drawio | 207 +++ .../content-updates/sync-subsurf-case1.drawio | 500 ++++++ .../content-updates/sync-subsurf-case2.drawio | 287 ++++ .../sync-to-desync-subsurf.drawio | 223 +++ .../sync-to-desync-transition.drawio | 203 +++ doc/book/images/wayland-architecture.gv | 36 + doc/book/images/x-architecture.gv | 53 + .../content-updates/content-update-legend.png | Bin 0 -> 15946 bytes .../simple-desynchronized-state-1.png | Bin 0 -> 2037 bytes .../simple-desynchronized-state-2.png | Bin 0 -> 6732 bytes .../simple-desynchronized-state-3.png | Bin 0 -> 1625 bytes .../simple-desynchronized-state-4.png | Bin 0 -> 7302 bytes .../simple-desynchronized-state-5.png | Bin 0 -> 12728 bytes .../simple-desynchronized-state-6.png | Bin 0 -> 2102 bytes .../simple-synchronized-state-1.png | Bin 0 -> 2117 bytes .../simple-synchronized-state-2.png | Bin 0 -> 2586 bytes .../simple-synchronized-state-3.png | Bin 0 -> 2989 bytes .../simple-synchronized-state-4.png | Bin 0 -> 17710 bytes .../simple-synchronized-state-5.png | Bin 0 -> 2209 bytes .../content-updates/sync-subsurf-case1-1.png | Bin 0 -> 26995 bytes .../content-updates/sync-subsurf-case1-2.png | Bin 0 -> 27535 bytes .../content-updates/sync-subsurf-case1-3.png | Bin 0 -> 22771 bytes .../content-updates/sync-subsurf-case1-4.png | Bin 0 -> 22017 bytes .../content-updates/sync-subsurf-case1-5.png | Bin 0 -> 10932 bytes .../content-updates/sync-subsurf-case2-1.png | Bin 0 -> 26210 bytes .../content-updates/sync-subsurf-case2-2.png | Bin 0 -> 25821 bytes .../content-updates/sync-subsurf-case2-3.png | Bin 0 -> 10069 bytes .../sync-to-desync-subsurf-1.png | Bin 0 -> 18621 bytes .../sync-to-desync-subsurf-2.png | Bin 0 -> 18069 bytes .../sync-to-desync-subsurf-3.png | Bin 0 -> 19371 bytes .../sync-to-desync-transition-1.png | Bin 0 -> 9299 bytes .../sync-to-desync-transition-2.png | Bin 0 -> 15177 bytes .../sync-to-desync-transition-3.png | Bin 0 -> 15872 bytes doc/book/src/images/icon.svg | 19 + doc/book/src/images/wayland-architecture.png | Bin 0 -> 26968 bytes doc/book/src/images/wayland.png | Bin 0 -> 5649 bytes doc/book/src/images/x-architecture.png | Bin 0 -> 28785 bytes doc/book/src/images/xwayland-architecture.png | Bin 0 -> 7611 bytes 40 files changed, 3254 insertions(+) create mode 100644 doc/book/images/content-updates/content-updates.drawio create mode 100644 doc/book/images/content-updates/simple-desynchronized.drawio create mode 100644 doc/book/images/content-updates/simple-synchronized.drawio create mode 100644 doc/book/images/content-updates/sync-subsurf-case1.drawio create mode 100644 doc/book/images/content-updates/sync-subsurf-case2.drawio create mode 100644 doc/book/images/content-updates/sync-to-desync-subsurf.drawio create mode 100644 doc/book/images/content-updates/sync-to-desync-transition.drawio create mode 100644 doc/book/images/wayland-architecture.gv create mode 100644 doc/book/images/x-architecture.gv create mode 100644 doc/book/src/images/content-updates/content-update-legend.png create mode 100644 doc/book/src/images/content-updates/simple-desynchronized-state-1.png create mode 100644 doc/book/src/images/content-updates/simple-desynchronized-state-2.png create mode 100644 doc/book/src/images/content-updates/simple-desynchronized-state-3.png create mode 100644 doc/book/src/images/content-updates/simple-desynchronized-state-4.png create mode 100644 doc/book/src/images/content-updates/simple-desynchronized-state-5.png create mode 100644 doc/book/src/images/content-updates/simple-desynchronized-state-6.png create mode 100644 doc/book/src/images/content-updates/simple-synchronized-state-1.png create mode 100644 doc/book/src/images/content-updates/simple-synchronized-state-2.png create mode 100644 doc/book/src/images/content-updates/simple-synchronized-state-3.png create mode 100644 doc/book/src/images/content-updates/simple-synchronized-state-4.png create mode 100644 doc/book/src/images/content-updates/simple-synchronized-state-5.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case1-1.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case1-2.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case1-3.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case1-4.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case1-5.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case2-1.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case2-2.png create mode 100644 doc/book/src/images/content-updates/sync-subsurf-case2-3.png create mode 100644 doc/book/src/images/content-updates/sync-to-desync-subsurf-1.png create mode 100644 doc/book/src/images/content-updates/sync-to-desync-subsurf-2.png create mode 100644 doc/book/src/images/content-updates/sync-to-desync-subsurf-3.png create mode 100644 doc/book/src/images/content-updates/sync-to-desync-transition-1.png create mode 100644 doc/book/src/images/content-updates/sync-to-desync-transition-2.png create mode 100644 doc/book/src/images/content-updates/sync-to-desync-transition-3.png create mode 100644 doc/book/src/images/icon.svg create mode 100644 doc/book/src/images/wayland-architecture.png create mode 100644 doc/book/src/images/wayland.png create mode 100644 doc/book/src/images/x-architecture.png create mode 100644 doc/book/src/images/xwayland-architecture.png diff --git a/doc/book/images/content-updates/content-updates.drawio b/doc/book/images/content-updates/content-updates.drawio new file mode 100644 index 00000000..5d780213 --- /dev/null +++ b/doc/book/images/content-updates/content-updates.drawio @@ -0,0 +1,1528 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/content-updates/simple-desynchronized.drawio b/doc/book/images/content-updates/simple-desynchronized.drawio new file mode 100644 index 00000000..c1adfd60 --- /dev/null +++ b/doc/book/images/content-updates/simple-desynchronized.drawio @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/content-updates/simple-synchronized.drawio b/doc/book/images/content-updates/simple-synchronized.drawio new file mode 100644 index 00000000..a478ae02 --- /dev/null +++ b/doc/book/images/content-updates/simple-synchronized.drawio @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/content-updates/sync-subsurf-case1.drawio b/doc/book/images/content-updates/sync-subsurf-case1.drawio new file mode 100644 index 00000000..385c6fd7 --- /dev/null +++ b/doc/book/images/content-updates/sync-subsurf-case1.drawio @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/content-updates/sync-subsurf-case2.drawio b/doc/book/images/content-updates/sync-subsurf-case2.drawio new file mode 100644 index 00000000..c1eaff66 --- /dev/null +++ b/doc/book/images/content-updates/sync-subsurf-case2.drawio @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/content-updates/sync-to-desync-subsurf.drawio b/doc/book/images/content-updates/sync-to-desync-subsurf.drawio new file mode 100644 index 00000000..7a72e0f6 --- /dev/null +++ b/doc/book/images/content-updates/sync-to-desync-subsurf.drawio @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/content-updates/sync-to-desync-transition.drawio b/doc/book/images/content-updates/sync-to-desync-transition.drawio new file mode 100644 index 00000000..9843acb6 --- /dev/null +++ b/doc/book/images/content-updates/sync-to-desync-transition.drawio @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/images/wayland-architecture.gv b/doc/book/images/wayland-architecture.gv new file mode 100644 index 00000000..f2c35075 --- /dev/null +++ b/doc/book/images/wayland-architecture.gv @@ -0,0 +1,36 @@ +digraph arch_wayland { + edge[ + fontname="DejaVu Sans", + dir="both", + arrowtail="dot", + arrowsize=.5, + fontname="DejaVu Sans", + fontsize="18", + ] + + node[ + color=none, + margin=0, + fontname="DejaVu Sans", + fontsize="18", + ] + + c1 [label=<
Wayland Client
>, URL="#c1"] + c2 [label=<
Wayland Client
>, URL="#c2"] + + comp [tooltip="Wayland Compositor", label=<

Wayland
Compositor

>, URL="#comp"] + + impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] + + c1 -> comp [taillabel="③", labeldistance=2.5, URL="#step_3"]; + c2 -> comp; + + comp -> c1 [label="②", URL="#step_2"]; + comp -> c2; + + comp -> impl [xlabel = "④", URL="#step_4"]; + comp -> impl [style = invis, label=" "]; + impl -> comp [xlabel = "①", URL="#step_1"]; + + c1 -> c2 [style=invis]; +} diff --git a/doc/book/images/x-architecture.gv b/doc/book/images/x-architecture.gv new file mode 100644 index 00000000..b223d1dc --- /dev/null +++ b/doc/book/images/x-architecture.gv @@ -0,0 +1,53 @@ +digraph arch_x { + edge[ + fontname="DejaVu Sans", + dir="both", + arrowtail="dot", + arrowsize=.5, + fontname="DejaVu Sans", + fontsize="18", + ] + + node[ + shape="none", + color=none, + margin=0, + fontname="DejaVu Sans", + fontsize="18", + ] + + { + rank=same; + c1 [label=<
X Client
>, URL="#c1"] + c3 [label=<
X Client
>, URL="#c3"] + } + c2 [label=<
X Client
>, URL="#c2"] + + { + rank=same; + xserver [tooltip="X Server", label=<

X Server

>, URL="#xserver"] + comp [tooltip="Compositor", label=<

Compositor

>, URL="#comp"] + } + + impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] + + c1 -> xserver [taillabel="③", labeldistance=2, URL="#step_3"]; + c2 -> xserver; + c3 -> xserver; + + xserver -> c1 [taillabel="②", labeldistance=2, URL="#step_2"]; + xserver -> c2; + xserver -> c3; + + xserver -> impl [taillabel="⑥", labeldistance=1.75, URL="#step_6"]; + xserver -> impl [style=invis, label=" "]; + impl -> xserver [taillabel="①", labeldistance=1.75, URL="#step_1"]; + + xserver -> comp [style=invis]; + xserver -> comp [taillabel="④", labeldistance=1.75, labelangle=-45, URL="#step_4"]; + comp -> xserver [taillabel="⑤", URL="#step_5"]; + comp -> xserver [style=invis] + + c1 -> c2 [style=invis]; + c3 -> c2 [style=invis]; + } diff --git a/doc/book/src/images/content-updates/content-update-legend.png b/doc/book/src/images/content-updates/content-update-legend.png new file mode 100644 index 0000000000000000000000000000000000000000..84f12e76aefa65bdc7fe98fb81bc168fdbb14416 GIT binary patch literal 15946 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
L23 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/simple-desynchronized-state-2.png b/doc/book/src/images/content-updates/simple-desynchronized-state-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd284cd6751882532c29984c00957ebdf323b8e GIT binary patch literal 6732 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 b%EZFT$O58=Z{hbWkRv@^{an^LB{Ts5an#hk literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/simple-desynchronized-state-4.png b/doc/book/src/images/content-updates/simple-desynchronized-state-4.png new file mode 100644 index 0000000000000000000000000000000000000000..83dcc063fac852fc513e3bfeb63a7450462cb454 GIT binary patch literal 7302 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMiGhJ(ugZlq1_lO&WRD&6h2cL4F4((#G6Mqxdx@v7 zEBh-(0Zs#%OHcMjFfd4`dAc};RNQ)dx3WSc^w9f{!FR8EDsXx;-BjrQtaiOar%Phn zX{FP~hgtLwT3qL0+hO#orSht{o{~%99*Gb($2oVt@0Iu(>a*uC&+Q!xAB*moaA1Lp zYoxK7(6-JsiqY*$wpabP2)cGV(#8L{+q2(4o0sqY^=0L%XAh5ChCZKjiRZ8YL&N*i zVsDrk8syEBL>Q(BEM{2HBEia_dPIXkL(z@VfzyzS!K)*XA;77JsX>ThC5za9Gwcid zxanHy)aCcHS$_Xvh}pbunuMs+lJvSeqF2LmB*oqsGZ*MC4(7*a?MofE>+52z>;C+h zXIp)*;&E@cm~K{1&Xn7yPo3JdX;V^C(xgd~($3F|4Gm4Ldpb2d?&OIRFD@=Vz9MjO zTiG2O6Q{7+l{cH^PUlbT+l$2}{NP2o|Dz})9gk8;#WxlhYe6y?l#i4j@ef<1cvu4el z85t0eP?vhRjrZAWS?e+m#Yc}HGgquxetuqk@!M60<3sApUUVn?&tv$ol`nen&!0cd z@0MI{GG8P6m(%Bhe*Zq}PyLPRtNk%|a)T}or+FM(fE?L5% z=;ZADe$VG~D^{$yySx1Kr0enZd++GIzjA)Ab@`DF!TP_i<5Mdcc0Ai!->s>om35$j z@%8of@+KJpWo6$U9&X>Bds|Fe+Pd=7lU=)Z`OY@;oo8cdZGHRk$DDh6A~_~bo~+zb z@#o|5RsmjK-pI(vP4lKqnKC`DN;BYi)ti*F8z;wy&i}DnAnE?W{ic@sy}L>aI+~@w zGci5m+Z9y-{}&aHT_^7&lT>}zlC?lw0u zDLFAgvH1D9xmKmC1e6R7KVDfGe9bFw-_K|M_J6;4^(}ss`Zjucu3p67PxSBwwbyZmfvQkYPuNFvLWstx=PvPJc?W5X+d?RDF5p8tU9>#WW|MVG2)$72I? zk4{TGXlKlD-N*`W*iAZ@RPy%L*2l;D-{0K)yx08Rj*N?ojvaH`xp&PP9c^uGH8nL& z&CG9aZia@2UdzwDxykkNmV?dg?7y!tJZQg=*kkwq&*$%Viv4SA|JHuLJAJ~04M|74 zcE8^j%@G(EXP0=W<3J#Dk7sA#Xe{l0|@6_u2d4!7~XzP9%C>C@hRes!j~r%JMZI4o;dhX|a2MT3VW%MM1*jW4%rszL$%Nimt7REdKD| z;8O4D*REd|7ZYRq?ZTj7ajXC0ty{Moo7t8wU3#*wCL$uj%d1O3$;9N#IqUa5U0t{K zR&Up-{QLF#>9+^%1Q|H`zU3Rby1Md87$p4t^|hIe_td#_b~QgfY|Fi!l$@;YKQAUc ze0%2QWhW=Ar>Cb^+sr#V+nigmsHmt#Kvh-sc%N)`UY?lK9P4twd$mzJ3KAnCA~yI7 zGwkY0lX$zH=Y84k_?nMLOJ84mdw;*Zot>Ssa`MANtwjNUt>5q2oOX8B-sngeP`I^*KYWWS=o*8 zkB8xMIii~eF8mI%j6oYyBR23eGVI&DI@QmX;g83~mFzTYQ;?N`@wabW_`fm61oIru zDBry-bFTPiu@`$L_1XQsHkavz(vge=iMESXYpxpfESu}Acv7(_`N)orvdwEgYfPDc z>eij(cPBnpUORtYe6^j4>XnIaI6V0>ZLhtudzW|X<`a*y6aI_S-A^-IHCcOi?}W7u z2Lu;0CP=tFZ8>#JwzuxK?8!c9t^5mmtLFr~w0bAxbYf1f?KQ2%W-sqgZV@;alz#Qd zs%=yMKWUzS!s43A+b@%s``cIUnymcsXHDSdMLA}(mt~#{N`KmNs-sYFsZNHti`R3a)-^)(HPP5C*I2B`# z$2_|py)PqcZ^UYMmtQsewoQHQxywT!Z~N`M?YDEbotwR}YSKE@47q;ycY$*Lm(QuK zzpmXf;ii_hqGuz6k{h$bw->Df*JXE{d;PU)Z`{msv)O0gmc8Dk*RtXE+rM$I#Q$cL z{GE1rz3r#v`{vDvKBDW?@%`KXr|XUX-QPP|{i~qct%p0$1*QLe{dIa->?G4_zlx~n zXw&J-Uhi7>x-HRSlB{jomk&Q{Y~|i1O0@lMiT1y8Hf780x6kCx#;m&^cfZ!BeD~eF z?YEx>vi@dgUZ;5^gF&LLaO00f0*eaW7u&^5Uu%E!i*fvqntk5S&sFNrzrnY>4D zy7x8Vx$<|b1M|P9+RgVr!nysnF8|>-o4wBkEx+^6_u=W(9UfdP0*0%O?C{wKio!g> zYdVuta%6v9zwdtR$dPm&ai=4$-)9!bFH7vOymckeIDM`~v0C914ckq}@Acc=iT=3V zd%E7sU2>wLQ;n2T3m!j++gtUs#%`zhXaCQwk^4*IuSrLq3tDa$Q*I%%?R3-M&5YMY zl1v!R956cU7dQ7xX>8fjT(juA6A!O_ex83$UHkFJ6Ft+n-`*SdzIu0A{F>GCZIW7+ zW&UO7xBGbW`TqF5yDq-ma?L*N%#1Z_*4(*sr=x>oX7jFf(eK4)N@{)A)^9%Ly~T-R z{q@&nyPwKEoys_Ckpn}lu3^;2BJqER{q}$NIv%Apsn=y@Dqs6ysl|zR4_~gIm%06B z%Q|kwZ*mqBY<@2P6#ak7jrxCUX70M1xB2F=J4Pj^HY|KyJ}q*!t~Ll%Kk8I}c6Rpm zjEhRK*Pn(m{am?KP|G z2F2H>&tLKN?c1d*S7zSal=}MG+UT7{Pp4=GpP3tF{V8q9ubO>vJNLedTfh11=9h;{ z4=-9>&-+0BY^ccM>kShoDqag)_%&+Dv(G16CL4-L%GudH4*R*5ZTaVkq35T{+gQBa zcKcBE_dbE7V|$KA>zU49Zy8ye^8e&2uGf0|{(L(9^73-~uUCTmZ9a9}pR4qF>zi%g zYuDsIX*w}&n%K?7%a!>{1d~h*7JXhkcd1|Tn~6R_+2y}if7+{P7r*{VO60z0cW#QV z-=n1;v#$EPZTq_WMhOkeGM9g^m$NH*(sQT%tXtmMji=`3|ND6NdiSeya}CSC-$?E^ zH8ZpO`{lB%Z2#Awl{PA$XK7Y)v4|N;NlY(`{WRyxkFRUimYar;Rk^7{K9ZGCy@lK=bflV7KwseiQJ{=+6ncDgWn&16% z^VL+%en#(7I7Y~yuv_c&qO|1a;r+W)0bosDPDmU?pR&!0by%R)(^Ji@E4!{^Yimlj#b-cou0KiZ-rIWw+_pUm@3%?6|Di8ftj<%D z`SO3xn$=&m%MR-*%j@YF-VX~6)s5b^CO0?t@g(c74&n=g*PoK|v73KB?Z&NTQ!l@a z*_t)={PXH}TOWPs-kQ9)O8s6<@tp^XiMG{Tihl3^|9P=4*6sZa_xC@ay3eoC*k82h z(}&JehuQ75V*h?~H`{$T>h_0|+wWVJFRYwfa&=WGx40e;KmT`YtWd+u{7uHviNm3_Kx zTlJis1(ECbZTwUk92{I&Sa{p$nbH!w`RAV&?Yx`Ue?0lzW+nlRaFNB6)qH1}WL`RJ zeqX1hqqlczzOb-xYJ|=AJH^^zYdF4jvh;4f``rBV-7T4y)jpR#J7Xg_`^BH1Z@3pP z4{bj_|Ap9Pi%-wj*>RRWKX=C@?b4Jx@%R7P%XM^hp09jyal;1=#Us<%?X!0W-+g#u z&dlq1f1d?fPLg?+z0<1m`s=Cg9`EHi7HGe^Qvcx~yHkhx{TgF!?d&HfCf5J^Jpbvp zUAuPO+gp8l&fQ(5*&EKQW*j=+HoyAS9NUX|{#&;Hz4Edo@AkH{HP&|7Zo8-6`FbI_ z-1f_ipWhD6oOR9ntW$^G$G^99?d`IU{jbeiS+h6yw%PK_H@C&FSARKASZ@CL=U=N# zeT|JxZrDo{_y+C@5)%^(3kU#pG^bBr9(2Ax_Q#D6S9V=#=@-5w`}WJr<@0B)pL{9L zV~5_`XziR8w($n)r$78GarZd3WaZmwo;&n(HQ%|wAyk2qa#Uxel zV?C0>Z#HwNy{=I#j+t1R5ty2~H1fwTM(2H7ox)EqP5pi^ur_6X?DgksYb?z^?&|Z3 z%HI6$sLh5Ke_m|3n7DAUleJVEtAlL$E9L_+&3@0O#5A7lS-Uy?{4CYqYAR)Mp>J=l zulqhbUQX-2YD>k3a@Xy5C*Jl<%+9^Gcg90GJF^)1b-QEq4jati;VKbK3Yl8^YM14T z6IR#uE?s(5N9NYrYW2{$mZdo-d*)vY3IEpdYV(E-DKB=+FWZ+5HiA7(&*0VPpKH#h z91`JBND7%+6Lb8dB^NK>(B1nyKI-yvic&& zlhuENFYhnCe(lzp>WzB#TJuk#Lr68C_X# z_Bu{QaZ!|Nhh`tIW%`{}u)NdEcBbsh7_!`>^q$=KJLW ziyg#&@)=s?-rBOQIqiwF_Wy~I^}@>M3U=Rp#^n8J@j~bJS*(5`aw}J^%PBuI`TFaf zmtwgTTUM-GXA@X?q$c}r_sKbL@@oa;&L=T3b!RVTT%ca}*Z5TFv!|;{()P5qxBJhr zxG2-O|8cMVnHm3GZhOUP{k>g&>t&z$zl44BED9IhzfqmN?{uWkr(@!bTr4u?GW+&# z+pJ|P*FUG=rFp5Xwe{_qy-T04o_~5;;r{I7Z|?IQZ{rLpGP8 z6vMUb#n(8eKl>KBInC9@<;3;U=jW!_>~<;aS3R$1IA2ppP|z^@+L~?cDH3gaK0f{Y zGo@#i_hf^WoE!>CCJcv;w{a^fiMvF}%O}NtF}AU(IoQOS_Omy8-rpC^+xLHeXZPzt z?(54gVmc8Qwz=o0O0?bdQF8!QDN|1@m{R3I73n%-Ymlkse# z|F@ccTe+Vp=TEh#&B_lB4xX-)xj#2MHh+qn#)Z<3i|@}{ow_?G`2NMmRwc3Vd#kqo z+_rP&!|gkR_hrxivY7wgzub2spCf&oI#zjf!;txaZNbm>_& zNw#wL-FG|IynUr|>B`FBwb`-e=B755>9+hOm?I*YW_toX%wwCF$Or7UfK9k)4 z{N_*Di2KKX9s3jQbK`}#FKU%n#OIo%OpURlB%s|KW!dieH^&*AZUk zz>pb!^5~|n>07^?>EFHNneO3B@82FOp2A%p;=AV3w6J~xtFJU6D8;ltjG zQoIb;3&Ss;Q&V&~Gik=Q;#aq$_Eda4(8&D!{QUUP(A2wii#~bmUYI#`)~sDsUtjtC z`lRN2*+$)#_y7Kd$9v?8GKH8#UT}p6_JD_Zoqxw&7zW6DfE7rnZ& z(*F0&^V4*rw`E<``kYxlx4WYwVnf2gNvhsfJC{Exw-L=0E#m$2E_s*na=8~u;oi&t zxqI;`X06P#oK)q)ak1X}|Avc+Y2SA))?RXLNwL-3qeqX(dl|K-9_U??rU$KZaL?`9vi7Q^87p8VqDi=l-D=jVkS%ZR=QZb9{Qbex5?_pM*IU3v|&cpkrRTb8--daK*{KC}G3`SI2Nj?59Rn`$vh_GSE%*|zW2PpiAS zWwWM=>JfvUjzU4jlZt|ml}vmmpEljuzk7C>nPl5Tol-7Eq5rmqCaNLV>K|_9zIN(q zvSX{jU%R)@J&IoJ%IiD6D4U-}U~ORNwg2ts?iQ}gZJbyB-9-7*m&wa-uRR#kcrtCX z>D!#FTQ^n8xD<~Zebl|l=f{nLnX~I=t)6vu^~PRnskQPac|@HmlJ~ToHn=`_ktw7# zdGY7P()HJW#;(6&qMKDX#Z*c8nA;V()n9+F+q)lBFFY(b!G3=0ZTk#!=dUVv4G%pm z+WDk3!ZPYWf24!ml+JVP0tF?nrp}mKHU0F}Teogqx}+4o-@N#8{-hN;cmAYqj>$jy z`s**hpHA+ruXf1^fxx2IyI$`&U3x~NMAPKd9RtjJ-+0% z-Ll(Zp-m@p&pCt?1&Oe{r8_<6E;@ar#8#ZjXa3P@0ma)+_+k|1w)_uswzN-$4x&mpn=&sBRj_2@kFD7x|MW{lqSo~WNaV!D2t zkKT65lwyfGV?sMYOx_(yPZ~SaA!5x92 z&*oIcUaz&AFFEU3iQ4|%->#jRY8o+n-L>Zyk;><59&VqMdHd5Qvr3gu!Ii})tr)l+ z7z7u4JrPj)c|+AwE6#03WowAq8dKG?tLJZ8^3$QRl0P!@y4(gKi*VNX2_56}% z9~;Lo^>(V{=T%K#Xw)7?r-fgeMUz29=5hpv9#O%eC74u257UwSbE z1A}UbYeY#(Vo9o1a#3nxNh*VpfsvW6fuXLUX^4@bm5Hg9iKVuIft7)Q{wkLpC>nC} zQ!>*k(KHxYS{a)|G<<7W(#ycWpaHj`Br`X)xFj*R0HMb$#K6+Z#KOwR0-}d+;rA>C P1_lOCS3j3^P6&6h2cL4F4((#G6Mqxdx@v7 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 aurjiM=;2%VJ&S>Xfx*+&&t;ucLK6Tuv==A< literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/simple-desynchronized-state-6.png b/doc/book/src/images/content-updates/simple-desynchronized-state-6.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb88d8189e24c11c018540d8068380b753031df GIT binary patch literal 2102 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/simple-synchronized-state-4.png b/doc/book/src/images/content-updates/simple-synchronized-state-4.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b9b3db323541330fcfecce76c831f62c97698a GIT binary patch literal 17710 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case1-1.png b/doc/book/src/images/content-updates/sync-subsurf-case1-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7ff8e42b9783c3ee6fb54c66828ec033cdd13d GIT binary patch literal 26995 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
- X vs. Wayland Architecture - - A good way to understand the Wayland architecture - and how it is different from X is to follow an event - from the input device to the point where the change - it affects appears on screen. - - - This is where we are now with X: - -
- X architecture diagram - - - - - - - - - - - - - - - -
- - - - - The kernel gets an event from an input - device and sends it to X through the evdev - input driver. The kernel does all the hard - work here by driving the device and - translating the different device specific - event protocols to the linux evdev input - event standard. - - - - - The X server determines which window the - event affects and sends it to the clients - that have selected for the event in question - on that window. The X server doesn't - actually know how to do this right, since - the window location on screen is controlled - by the compositor and may be transformed in - a number of ways that the X server doesn't - understand (scaled down, rotated, wobbling, - etc). - - - - - The client looks at the event and decides - what to do. Often the UI will have to change - in response to the event - perhaps a check - box was clicked or the pointer entered a - button that must be highlighted. Thus the - client sends a rendering request back to the - X server. - - - - - When the X server receives the rendering - request, it sends it to the driver to let it - program the hardware to do the rendering. - The X server also calculates the bounding - region of the rendering, and sends that to - the compositor as a damage event. - - - - - The damage event tells the compositor that - something changed in the window and that it - has to recomposite the part of the screen - where that window is visible. The compositor - is responsible for rendering the entire - screen contents based on its scenegraph and - the contents of the X windows. Yet, it has - to go through the X server to render this. - - - - - The X server receives the rendering requests - from the compositor and either copies the - compositor back buffer to the front buffer - or does a pageflip. In the general case, the - X server has to do this step so it can - account for overlapping windows, which may - require clipping and determine whether or - not it can page flip. However, for a - compositor, which is always fullscreen, this - is another unnecessary context switch. - - - - - - As suggested above, there are a few problems with this - approach. The X server doesn't have the information to - decide which window should receive the event, nor can it - transform the screen coordinates to window-local - coordinates. And even though X has handed responsibility for - the final painting of the screen to the compositing manager, - X still controls the front buffer and modesetting. Most of - the complexity that the X server used to handle is now - available in the kernel or self contained libraries (KMS, - evdev, mesa, fontconfig, freetype, cairo, Qt etc). In - general, the X server is now just a middle man that - introduces an extra step between applications and the - compositor and an extra step between the compositor and the - hardware. - - - In Wayland the compositor is the display server. We transfer - the control of KMS and evdev to the compositor. The Wayland - protocol lets the compositor send the input events directly - to the clients and lets the client send the damage event - directly to the compositor: - -
- Wayland architecture diagram - - - - - - - - - - - - - -
- - - - - The kernel gets an event and sends - it to the compositor. This - is similar to the X case, which is - great, since we get to reuse all the - input drivers in the kernel. - - - - - The compositor looks through its - scenegraph to determine which window - should receive the event. The - scenegraph corresponds to what's on - screen and the compositor - understands the transformations that - it may have applied to the elements - in the scenegraph. Thus, the - compositor can pick the right window - and transform the screen coordinates - to window-local coordinates, by - applying the inverse - transformations. The types of - transformation that can be applied - to a window is only restricted to - what the compositor can do, as long - as it can compute the inverse - transformation for the input events. - - - - - As in the X case, when the client - receives the event, it updates the - UI in response. But in the Wayland - case, the rendering happens in the - client, and the client just sends a - request to the compositor to - indicate the region that was - updated. - - - - - The compositor collects damage - requests from its clients and then - recomposites the screen. The - compositor can then directly issue - an ioctl to schedule a pageflip with - KMS. - - - - - - -
-
- Wayland Rendering - - One of the details I left out in the above overview - is how clients actually render under Wayland. By - removing the X server from the picture we also - removed the mechanism by which X clients typically - render. But there's another mechanism that we're - already using with DRI2 under X: direct rendering. - With direct rendering, the client and the server - share a video memory buffer. The client links to a - rendering library such as OpenGL that knows how to - program the hardware and renders directly into the - buffer. The compositor in turn can take the buffer - and use it as a texture when it composites the - desktop. After the initial setup, the client only - needs to tell the compositor which buffer to use and - when and where it has rendered new content into it. - - - - This leaves an application with two ways to update its window contents: - - - - - - Render the new content into a new buffer and tell the compositor - to use that instead of the old buffer. The application can - allocate a new buffer every time it needs to update the window - contents or it can keep two (or more) buffers around and cycle - between them. The buffer management is entirely under - application control. - - - - - Render the new content into the buffer that it previously - told the compositor to to use. While it's possible to just - render directly into the buffer shared with the compositor, - this might race with the compositor. What can happen is that - repainting the window contents could be interrupted by the - compositor repainting the desktop. If the application gets - interrupted just after clearing the window but before - rendering the contents, the compositor will texture from a - blank buffer. The result is that the application window will - flicker between a blank window or half-rendered content. The - traditional way to avoid this is to render the new content - into a back buffer and then copy from there into the - compositor surface. The back buffer can be allocated on the - fly and just big enough to hold the new content, or the - application can keep a buffer around. Again, this is under - application control. - - - - - - In either case, the application must tell the compositor - which area of the surface holds new contents. When the - application renders directly to the shared buffer, the - compositor needs to be noticed that there is new content. - But also when exchanging buffers, the compositor doesn't - assume anything changed, and needs a request from the - application before it will repaint the desktop. The idea - that even if an application passes a new buffer to the - compositor, only a small part of the buffer may be - different, like a blinking cursor or a spinner. - -
-
- Accelerated GPU Buffer Exchange - - Clients - exchange - GPU buffers with the compositor as dma-buf file descriptors, which are universal handles - that are independent of any particular rendering API or memory allocator. The - linux-dmabuf-v1 - protocol is used to turn one or more dma-buf FDs into a - wl_buffer. - - - If the client uses the - Vulkan - or - EGL - (via - wayland-egl) - window-system integration - (WSI), this is done transparently by the WSI. - - - Clients can alternatively allocate and import dma-bufs themselves - using the GBM library, Vulkan, udmabuf, or dma-buf heaps. - - - - - Using GBM, the client can allocate a gbm_bo and export one or more - dma-buf FDs from it. - - - - - Using Vulkan, the client can create a VkDeviceMemory object and use - VK_EXT_external_memory_dma_buf - and - VK_EXT_image_drm_format_modifier - to export a dma-buf FD from it. - - - - - udmabuf - can be used to create dma-buf FDs from linear host memory. - - - - - Dma-buf heaps - can be used by privileged applications to create dma-buf FDs on embedded - devices. - - - - - Compositors use - VK_EXT_external_memory_dma_buf - and - VK_EXT_image_drm_format_modifier - or - EGL_EXT_image_dma_buf_import - and - EGL_EXT_image_dma_buf_import_modifiers - to import the dma-bufs provided by the client into their own Vulkan or - EGL renderers. - - - Clients do not need to wait for the GPU to finish rendering before submitting - dma-bufs to the compositor. Clients can use the - linux-drm-syncobj-v1 - protocol to exchange DRM synchronization objects with the compositor. These objects - are used to asynchronously signal ownership transfer of buffers from clients to the - compositor and vice versa. The WSIs do this transparently. - - - If the linux-drm-syncobj-v1 protocol is not supported by the compositor, clients - and compositors can use the - DMA_BUF_IOCTL_EXPORT_SYNC_FILE - and - DMA_BUF_IOCTL_IMPORT_SYNC_FILE - ioctls to access and create implicit synchronization barriers. - -
-
- Display Programming - - Compositors enumerate DRM KMS devices using - udev. - Udev also notifies compositors of KMS device and display hotplug events. - - - Access to DRM KMS device ioctls is privileged. Since compositors usually run as - unprivileged applications, they typically gain access to a privileged file - descriptor using the - TakeDevice - method provided by logind. - - - Using the file descriptor, compositors use KMS - ioctls - to enumerate the available displays. - - - Compositors use - atomic mode setting - to change the buffer shown by the display, to change the display's resolution, to - enable or disable HDR, and so on. - -
- diff --git a/doc/publican/Color.xml b/doc/publican/Color.xml deleted file mode 100644 index ceee779e..00000000 --- a/doc/publican/Color.xml +++ /dev/null @@ -1,139 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - - Color management - -
- Overview - - - Color management in Wayland considers only displays. All pictures in - Wayland are always display-referred, meaning that the pixel values are - intended as-is for some specific display where they would produce the - light emissions (stimuli) the picture's - author desired. Wayland does not support displaying "raw" camera or - scanner images as they are not display-referred, nor are they even - pictures without complex and subjective processing. - - - Stimuli — the picture itself — are only half of the picture reproduction. - The other half is the environment where a display is viewed. A striking - example is comparing a brightly lit office to a dark movie theater, the - stimuli required to produce a good reading of the picture is greatly - different. Therefore display-referred does not include only the display - but the viewing environment as well. - - - Window systems have been very well capable of operating without any - explicit consideration to color management. This is because there used to - be the implicit assumption of the standard display, the sRGB display, - which all computer monitors implemented, more or less. The viewing - environment was and still is accounted by adjusting the display and/or the - room to produce a workable experience. Pictures are authored on a computer - system by drawing, painting and adjusting the picture until it looks right - on the author's monitor. This implicitly builds the standard display and - environment assumption into the picture data. Deviations from the sRGB - specification were minor enough that they often did not matter if not in a - professional context like the printing industry. Displaying video material - required some more attention to the details, because video and television - standards differ enough from the sRGB display. What really made explicit - color management a hard requirement for entertainment is the coming of - wide color gamut (WCG) and high dynamic range (HDR) materials and - displays. - - - The color management design in Wayland follows the general Wayland design - principles: compositors tell clients what would be the optimal thing to - do, clients tell the compositors what kind of pictures they are actually - producing, and then compositors display those pictures the best they can. - -
- -
- Protocol Interfaces - - - Color management interfaces in Wayland and divided into two protocols: - color-management - and - color-representation. - They are designed to work together, but they can also be used - independently when the other one is not needed. - - -
- Color-management - - - Color management protocol has two main purposes. First, it puts the - responsibility of color management on the compositor. This means that - clients do not necessarily need to care about color management at all, - and can display just fine by using the traditional standard display - assumption even when the actual display is wildly different. Clients - can also choose to target some other assumed display and let the - compositor handle it, or they can explicitly render for the actual - display at hand. Second, when the window system has multiple different - monitors, and a wl_surface happens to span more than one monitor, the - compositor can display the surface content correctly on all spanned - monitors simultaneously, as much as physically possible. - - - Color-management protocol concentrates on colorimetry: when you have a - pixel with RGB values, what stimulus do those values represent. The - stimulus definition follows the CIE 1931 two-degree observer model. Some - core concepts here are color primaries, white point, transfer function, - and dynamic range. The viewing environment is represented in an - extremely simplified way as the reference white luminance. The - connection between pixel RGB values and stimulus plus viewing - environment is recorded in an image description - object. Clients can create image description objects and tag - wl_surfaces with them, to indicate what kind of surface - content there will be. Clients can also ask what image description the - compositor would prefer to have on the wl_surface, and that - preference can change over time, e.g. when the wl_surface - is moved from one - wl_output to another. Following the compositor's preference - may provide advantages in image quality and power consumption. - - - Image description objects can come in two flavors: parametric and - ICC-based. The above was written with parametric image descriptions in - mind, and they have first-class support for HDR. ICC-based image - descriptions are wrapping an ICC profile and have no other data. ICC - profiles are the standard tool for standard dynamic range (SDR) display - color management. This means the capabilities between the two flavors - differ, and one cannot always be replaced by the other. Compositor - support for each flavor is optional. - -
- -
- Color-representation - - - Color-representation protocol deals with (potentially sub-sampled) - YCbCr-RGB conversion, quantization range, and the inclusion of alpha in - the RGB color channels, a.k.a. pre-multiplication. There are several - different specifications on how an YCbCr-like (including ICtCp) signal, - with chroma sub-sampling or not, is created from a full-resolution RGB - image. Again, a client can tag a wl_surface with - color-representation metadata to tell the compositor what kind of pixel - data will be displayed through the wl_surface. - - - The main purpose of color-representation is to correctly off-load the - YCbCr-RGB conversion to the compositor, which can then opportunistically - off-load it further to very power-efficient fixed-function circuitry in - a display controller. This can significantly reduce power consumption - when watching videos compared to using a GPU for the same, and on some - embedded hardware platforms it is a hard requirement for processing high - resolution video. - -
-
-
diff --git a/doc/publican/Compositors.xml b/doc/publican/Compositors.xml deleted file mode 100644 index 7a7bdaa0..00000000 --- a/doc/publican/Compositors.xml +++ /dev/null @@ -1,128 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - Types of Compositors - - - Compositors come in different types, depending on which - role they play in the overall architecture of the OS. - For instance, a - system compositor - can be used for booting the system, handling multiple user switching, a - possible console terminal emulator and so forth. A different compositor, a - session compositor - would provide the actual desktop environment. There are many ways for - different types of compositors to co-exist. - - - In this section, we introduce three types of Wayland compositors relying - on libwayland-server. - - -
- System Compositor - - A system compositor can run from early boot until shutdown. - It effectively replaces the kernel vt system, and can tie in - with the systems graphical boot setup and multiseat support. - - - A system compositor can host different types of session - compositors, and let us switch between multiple sessions - (fast user switching, or secure/personal desktop switching). - - - A linux implementation of a system compositor will typically - use libudev, egl, kms, evdev and cairo. - - - For fullscreen clients, the system compositor can reprogram the - video scanout address to read directly from the client provided - buffer. - -
-
- Session Compositor - - A session compositor is responsible for a single user session. - If a system compositor is present, the session compositor will - run nested under the system compositor. Nesting is feasible because - the protocol is asynchronous; roundtrips would be too expensive - when nesting is involved. If no system compositor is present, a - session compositor can run directly on the hardware. - - - X applications can continue working under a session compositor - by means of a root-less X server that is activated on demand. - - - Possible examples for session compositors include - - - - gnome-shell - - - - - moblin - - - - - kwin - - - - - kmscon - - - - - rdp session - - - - - Weston with X11 or Wayland backend is a session compositor nested - in another session compositor. - - - - - fullscreen X session under Wayland - - - - -
-
- Embedding Compositor - - X11 lets clients embed windows from other clients, or lets clients - copy pixmap contents rendered by another client into their window. - This is often used for applets in a panel, browser plugins and similar. - Wayland doesn't directly allow this, but clients can communicate GEM - buffer names out-of-band, for example, using D-Bus, or command line - arguments when the panel launches the applet. Another option is to - use a nested Wayland instance. For this, the Wayland server will have - to be a library that the host application links to. The host - application will then pass the Wayland server socket name to the - embedded application, and will need to implement the Wayland - compositor interface. The host application composites the client - surfaces as part of it's window, that is, in the web page or in the - panel. The benefit of nesting the Wayland server is that it provides - the requests the embedded client needs to inform the host about buffer - updates and a mechanism for forwarding input events from the host - application. - - - An example for this kind of setup is firefox embedding the flash - player as a kind of special-purpose compositor. - -
-
diff --git a/doc/publican/Content_Updates.xml b/doc/publican/Content_Updates.xml deleted file mode 100644 index 30c4ed33..00000000 --- a/doc/publican/Content_Updates.xml +++ /dev/null @@ -1,460 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - - Content Updates - -
- Overview - - - In the Wayland protocol, requests are asynchronous but take effect - immediately when the compositor receives them. However, some requests on - surfaces are not applied immediately but are instead double-buffered to - allow atomic changes. These double-buffered changes are committed through - the wl_surface.commit request, which creates a Content Update. - - - - Content Updates encapsulate all double-buffered state changes and can be - applied by the compositor. The complexity arises when considering - subsurfaces, which can operate in synchronized mode. When a subsurface is - synchronized, its Content Updates must be applied atomically together with - the parent surface's state. This synchronization can extend through an - entire tree of subsurfaces, where child subsurfaces inherit the - synchronized behavior from their parents. - - - - Historically, Content Updates from synchronized subsurfaces were merged - into the pending state of the parent surface on commit. However, the - introduction of constraints—which can defer the application of Content - Updates—necessitated a more sophisticated model. This led to the - implementation of per-surface queues of Content Updates, with dependencies - between Content Updates across different queues. This queuing model - maintains backwards compatibility with the earlier approach of merging - Content Updates into the parent's pending state on commit. - - - - The core protocol defines the semantics of Content Updates using - per-surface queues, but compositors that do not need to support constraints - may implement the simpler legacy model where synchronized subsurface states - are merged directly into the parent's pending state. - -
- -
- Rules - - - The core protocol specifies the behavior in wl_subsurface and - wl_surface.commit. The behavior can be summarized by the following rules: - - - - - - Content Updates (CU) contain all double-buffered state of the surface and - selected state from their direct children. - - - - - Surfaces which are effectively synchronized create Synchronized - Content Updates (SCU), otherwise they create Desync Content Updates - (DCU). - - - - - When a CU is created, it gets a dependency on the previous CU of the - same queues (if it exists). - - - - - When a CU is created, it gets a dependency on the last SCU of direct - child surfaces that are not reachable (if they exists). - - - - - The CUs and their dependencies form a DAG, where CUs are nodes and - dependencies are edges. - - - - - All DCUs starting from the front of the queues until the first SCU or - the back of the queue is reached are candidates. - - - - - If the maximal DAG that's reachable from a candidate (candidate DAG) - does not have any constraints, then this DAG can be applied. - - - - - A DAG is applied atomically by recursively applying a content update - without dependencies and removing it from the DAG. - - - - - Surfaces transition from effectively sync to effectively desync after - their parents. - - - - - When a surface transitions to effectively desync, all SCUs in its - queue which are not reachable by a DCU become DCUs. - - - -
- -
- Examples - - - These examples should help to build an intuition for how content updates - actually behave. They cover the interesting edge cases, such as - subsurfaces with constraints, and transitioning from a sync subsurface to - a desync one. - - - In all the examples below, the surface T1 refers to a toplevel surface, - SS1 refers to a sub-surface which is a child of T1, and SS2 refers to a - sub-surface which is a child of SS1. - - -
- Legend - - - - - -
- -
- Simple Desynchronized Case - - - - - - - SS2 is effectively desynchronized and commits. This results in the - desynchronized content update (DCU) 1. - - - - - - - - - - DCU 1 is a candidate, and the candidate DAG - reachable from DCU 1 is only - DCU 1 itself. DCU 1 and - thus the candidate DAG does not have any constraints and can be - applied. - - - - - - - - - - The content updates of the candidate DAG get applied to the surface - atomically. - - - - - - - - - - T1 commits a DCU with a buffer-sync constraint. - It is a candidate but its DAG can't be applied because it contains a - constraint. - - - - - - - - - - T1 commits another CU (DCU 3) which is added at - the end of the queue, with a dependency to the previous CU (DCU - 2). Both DCU 2 and DCU - 3 are candidates, but both DAGs contain DCU - 2 with a constraint, and can't be applied. - - - - - - - - - - When the constraint gets cleared, both DAGs can be applied to the - surface atomitcally (either only 2, or - 2 and 3). - - - -
- -
- Simple Synchronized Case - - - - - - - SS1 and SS2 are effectively synchronized. SS2 commits SCU 1. - - - - - - - - - - SS1 commits SCU 2. The direct child surfaces SS2 has the last SCU 1 in its queue, which is not reachable. This creates a dependency from SCU 2 to SCU 1. - - - - - - - - - - SS1 commits SCU 3. The direct child surfaces SS2 has the last SCU 1 in its queue, which is already reachable by SCU 2. No dependency to SCU 1 is created. A dependency to the previous CU of the same queue (SCU 2) is created. - - - - - - - - - - T1 commit DCU 4. It is a candidate, its DAG does not contain any constraint and it can be applied. - - - - - - - - - - The DAG gets applied to the surfaces atomically. - - - -
- -
- Complex Synchronized Subsurface Case 1 - - - - - - - Every DCU (1 and 6) contain - CUs with constraints in their candidate DAG - - - - - - - - - - Waiting until the buffer-sync constrain on CU - 1 is cleared, the candidate DAG of CU - 1 does not contain constraints and can be applied - - - - - - - - - - That leaves the candidate DAG of CU 6 which still - contains another CU with a buffer-sync constrain - - - - - - - - - - Waiting until the buffer-sync constrain on CU - 6 is cleared, the candidate DAG of - 6 does not contain CUs with constraints and can - be applied. - - - - - - - - - - There is no DCU left and no constraint remaining. Nothing more can be - applied without a new CU. - - - -
- -
- Complex Synchronized Subsurface Case 2 - - - - - - - Both DCUs (1 and 6) have a - reachable DAG containing CU 1 with a constraint - - - - - - - - - - Waiting until the buffer-sync constrain on - 1 is cleared, both DAGs contain no CU with - constraints and can be applied in any order - - - - - - - - - - That leaves the same state as in the previous case - - - -
- -
- Synchronized to Desynchronized Subsurface - - - - - - - There is one DCU (4) with its reachable DAG - that cannot be applied because CU 4 contains a - constraint - - - - - - - - - - Surface SS1 transitions from effectively - synchronized to effectively desynchronized. SCU - 2 is reachable by DCU 4 so - nothing changes. - - - - - - - - - - Surface SS1 provides a new DCU - (5) but because the CU before - (2) is a Synchronized CU, it is not a candidate - - - -
- -
- Synchronized to Desynchronized Transition - - - - - - - There are four SCUs and all surfaces are effectively synchronized. - - - - - - - - - - Surface SS1 transitions to effectively - desynchronized and SCU 2 becomes a DCU because - it is not reachable from a DCU - - - - - - - - - - Surface SS2 transitions to effectively - desynchronized. SCUs 3 and - 4 become DCUs because they are not reachable - from a DCU. SCU 1 does not change because it is - reachable by DCU 2. - - - -
- -
-
diff --git a/doc/publican/Introduction.xml b/doc/publican/Introduction.xml deleted file mode 100644 index f2a82744..00000000 --- a/doc/publican/Introduction.xml +++ /dev/null @@ -1,116 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - Introduction -
- Motivation - - Most Linux and Unix-based systems rely on the X Window System (or - simply X) as the low-level protocol for building - bitmap graphics interfaces. On these systems, the X stack has grown to - encompass functionality arguably belonging in client libraries, - helper libraries, or the host operating system kernel. Support for - things like PCI resource management, display configuration management, - direct rendering, and memory management has been integrated into the X - stack, imposing limitations like limited support for standalone - applications, duplication in other projects (e.g. the Linux fb layer - or the DirectFB project), and high levels of complexity for systems - combining multiple elements (for example radeon memory map handling - between the fb driver and X driver, or VT switching). - - - Moreover, X has grown to incorporate modern features like offscreen - rendering and scene composition, but subject to the limitations of the - X architecture. For example, the X implementation of composition adds - additional context switches and makes things like input redirection - difficult. - - - - - - - - X architecture diagram - - - - - The diagram above illustrates the central role of the X server and - compositor in operations, and the steps required to get contents on to - the screen. - - - Over time, X developers came to understand the shortcomings of this - approach and worked to split things up. Over the past several years, - a lot of functionality has moved out of the X server and into - client-side libraries or kernel drivers. One of the first components - to move out was font rendering, with freetype and fontconfig providing - an alternative to the core X fonts. Direct rendering OpenGL as a - graphics driver in a client side library went through some iterations, - ending up as DRI2, which abstracted most of the direct rendering - buffer management from client code. Then cairo came along and provided - a modern 2D rendering library independent of X, and compositing - managers took over control of the rendering of the desktop as toolkits - like GTK+ and Qt moved away from using X APIs for rendering. Recently, - memory and display management have moved to the Linux kernel, further - reducing the scope of X and its driver stack. The end result is a - highly modular graphics stack. - - -
- -
- The compositing manager as the display server - - Wayland is a new display server and compositing protocol, and Weston - is the implementation of this protocol which builds on top of all the - components above. We are trying to distill out the functionality in - the X server that is still used by the modern Linux desktop. This - turns out to be not a whole lot. Applications can allocate their own - off-screen buffers and render their window contents directly, using - hardware accelerated libraries like libGL, or high quality software - implementations like those found in Cairo. In the end, what’s needed - is a way to present the resulting window surface for display, and a - way to receive and arbitrate input among multiple clients. This is - what Wayland provides, by piecing together the components already in - the eco-system in a slightly different way. - - - X will always be relevant, in the same way Fortran compilers and VRML - browsers are, but it’s time that we think about moving it out of the - critical path and provide it as an optional component for legacy - applications. - - - Overall, the philosophy of Wayland is to provide clients with a way to - manage windows and how their contents are displayed. Rendering is left - to clients, and system wide memory management interfaces are used to - pass buffer handles between clients and the compositing manager. - - - - - - - - Wayland architecture diagram - - - - - The figure above illustrates how Wayland clients interact with a - Wayland server. Note that window management and composition are - handled entirely in the server, significantly reducing complexity - while marginally improving performance through reduced context - switching. The resulting system is easier to build and extend than a - similar X system, because often changes need only be made in one - place. Or in the case of protocol extensions, two (rather than 3 or 4 - in the X case where window management and/or composition handling may - also need to be updated). - -
-
diff --git a/doc/publican/Message_XML.xml b/doc/publican/Message_XML.xml deleted file mode 100644 index 0188eead..00000000 --- a/doc/publican/Message_XML.xml +++ /dev/null @@ -1,928 +0,0 @@ - - -%BOOK_ENTITIES; - -protocol"> -copyright"> -description"> -interface"> -enum"> -entry"> -request"> -event"> -arg"> - - - -]> - - - Message Definition Language - -
- Overview - - - The fundamentals of the Wayland protocol are explained in - . This chapter formally defines the - language used to define Wayland protocols. - - - Wayland is an object-oriented protocol. Each object follows exactly - one interface. An interface is a collection of message and enumeration - definitions. A message can be either a request (sent by a client) - or an event (sent by a server). A message can have arguments. - All arguments are typed. - -
- -
- XML Elements - -
- protocol - - protocol ::= (©right;?, &description;? &interface;+) - - - protocol is the root element in a Wayland protocol XML file. - Code generation tools may optionally use the protocol - name in API symbol names. The XML file name should be - similar to the protocol name. - - - The &description; element should be used to document the intended - purpose of the protocol, give an overview, and give any development - stage notices if applicable. - - - The ©right; element should be used to indicate the copyrights and - the license of the XML file. - - - - Required attributes - - - - name="cname" - - - - The name of the protocol (a.k.a protocol extension). - &cname-requirements; - - - The name should be globally unique. Protocols to be included in - wayland-protocols - must follow the naming rules set there. Other protocols should use - a unique prefix for the name, e.g. referring to the owning project's - name. - - - - -
- - - -
- description - - - Parent elements: &protocol;, &interface;, &request;, &event;, - &arg;, &enum;, &entry; - - - description ::= #PCDATA - - - Contains human-readable documentation for its parent element. - May contain formatted text, including paragraphs and bulleted - lists. - - - - Optional attributes - - - - summary="summary" - - - - A short (half a line at most) description of the documented - element. - - - When a &description; element is used, it is recommended to - not use the summary attribute of the parent - element. - - - - -
- -
- interface - - - Parent elements: &protocol; - - - interface ::= (&description;?, (&request;|&event;|&enum;)+) - - - An interface element contains the &request;s and &event;s that form the - interface. Enumerations can also be defined with &enum; elements. - These all belong into the namespace of the interface. Code generation - tools may use the interface name in API symbol names. - - - Interfaces form an ancestry tree. Aside from - , new protocol objects are - always created through an existing protocol object that may be referred to - as the factory object. - This can happen in one of two ways: the factory object's interface either - defines or does not define the new object's interface. - - - When the factory interface defines the new object's interface, the new - object also inherits the factory object's interface version number. - This number defines the interface version of the new object. - The factory object is referred to as - the parent object and the factory interface is - referred to as the parent interface. This - forms the ancestry tree of interfaces. - - - When the factory interface does not define the new object's interface, - both the interface name and the version must be communicated explicitly. - The foremost example of this is - . - In this case the terms "parent" or "ancestor" are not used. Interfaces - that are advertised through - are called global interfaces, or globals for short. - - - If objects having the interface can cause protocol errors, the protocol - error codes must be defined within the interface with an &enum; - element with its name set to "error". - Protocol error codes are always specific to the interface of the object - referred to in . - - - The &description; element should be used to describe the purpose and - the general usage of the interface. - - - - Required attributes - - - - name="cname" - - - - The name of the interface. &cname-requirements; - The name must be unique in the &protocol;, and preferably it should - also be globally unique to avoid API conflicts in language bindings - of multiple protocols. - - - Protocols to be included in - wayland-protocols - must follow the interface naming rules set there. Other protocols - should use a unique prefix for the name, e.g. referring to the owning - project's name. - - - - - - version="V" - - - - The interface's latest version number V must - be an integer greater than zero. An interface element defines - all versions of the interface from 1 to V - inclusive. The contents of each interface version are defined in each of - the &request;, &event;, &enum; and &entry; elements using the attributes - since and deprecated-since, and - in the specification text. - - - When an interface is extended, the version number must be incremented - on all the interfaces part of the same interface ancestry tree. - The exception to this rule are interfaces which are forever stuck - to version 1, which is usually caused by having multiple parent - interfaces with independent ancestor global interfaces. - - - A protocol object may have any defined version of the interface. - The version of the object is determined at runtime either - by inheritance from another protocol object or explicitly. - - - It is possible for a protocol object to have a version higher than - defined by its interface. This may happen when the interface is - stuck at version 1 as per above. It may also happen when a protocol - XML file has not been thoroughly updated as required. In such cases - the object shall function as with the highest defined interface - version. - - - - -
- -
- request - - - Parent elements: &interface; - - - request ::= (&description;?, &arg;*) - - - Defines a request, a message from a client to a server. - Requests are always associated with a specific protocol object. - - - Requests are automatically assigned opcodes in the order they - appear inside the &interface; element. Therefore the only - backwards-compatible way to add requests to an interface is to - add them to the end. Any &event; elements do not interfere - with request opcode assignments. - - - The &arg; elements declare the request's arguments. - There can be 0 to 20 arguments for a request. - The order of &arg; inside the request element defines the order of - the arguments on the wire. All declared arguments are mandatory, - and extra arguments are not allowed on the wire. - - - The &description; element should be used to document the request. - - - - Required attributes - - - - name="cname" - - - - The name of the request. &cname-requirements; - The name must be unique within all requests and &event;s in the - containing &interface;. - - - Code and language binding generators may use the name in the API - they create. The name of the containing - &interface; provides the namespace for requests. - - - - - - - Optional attributes - - - - type="destructor" - - - - When this attribute is present, the request is a destructor: - it shall destroy the protocol object it is sent on. Protocol IPC - libraries may use this for bookkeeping protocol object lifetimes. - - - Libwayland-client uses this information to ignore incoming &event;s - for destroyed protocol objects. Such events may occur due to a - natural race condition between the client destroying a protocol - object and the server sending events before processing the - destroy request. - - - - - - since="S" - - - - S must be an integer greater than zero. - If since is not specified, - since="1" is assumed. - - - This request was added in &interface; version - S. The request does not exist if the - protocol object has a bound version smaller than - S. Attempts to use it in such a case - shall raise the protocol error - wl_display.error.invalid_method. - - - - - - deprecated-since="D" - - - - D must be an integer greater than the - value of since. - If deprecated-since is not specified, then - the request is not deprecated in any version of the containing - &interface;. - - - This request was deprecated in &interface; version - D and above, and should not be sent on - protocol objects of such version. This is informational. - Compositors must still be prepared to handle the - request unless specified otherwise. - - - - -
- -
- event - - - Parent elements: &interface; - - - event ::= (&description;?, &arg;*) - - - Defines an event, a message from a server to a client. - Events are always associated with a specific protocol object. - - - Events are automatically assigned opcodes in the order they - appear inside the &interface; element. Therefore the only - backwards-compatible way to add events to an interface is to - add them to the end. Any &request; elements do not interfere - with event opcode assignments. - - - The &arg; elements declare the event's arguments. - There can be 0 to 20 arguments for an event. - The order of &arg; inside the event element defines the order of - the arguments on the wire. All declared arguments are mandatory, - and extra arguments are not allowed on the wire. - - - The &description; element should be used to document the event. - - - - Required attributes - - - - name="cname" - - - - The name of the event. &cname-requirements; - The name must be unique within all &request;s and events in the - containing &interface;. - - - Code and language binding generators may use the name in the API - they create. The name of the containing - &interface; provides the namespace for events. - - - - - - - Optional attributes - - - - type="destructor" - - - - When this attribute is present, the event is a destructor: - it shall destroy the protocol object it is sent on. Protocol IPC - libraries may use this for bookkeeping protocol object lifetimes. - - - - Destructor events are an underdeveloped feature in Wayland. - They can be used only on client-created protocol objects, and - it is the protocol designer's responsibility - to design such a message exchange that race conditions cannot - occur. The main problem would be a client sending a request at the - same time as the server is sending a destructor event. The - server will consider the protocol object to be already invalid - or even recycled when it proceeds to process the request. - This often results in protocol errors, but under specific - conditions it might also result in silently incorrect behavior. - - - Destructor events should not be used in new protocols. - If a destructor event is necessary, the simplest way to avoid - these problems is to have the &interface; not contain any - &request;s. - - - - - - - since="S" - - - - S must be an integer greater than zero. - If since is not specified, - since="1" is assumed. - - - This event was added in &interface; version - S. The event does not exist if the - protocol object has a bound version smaller than - S. - - - - - - deprecated-since="D" - - - - D must be an integer greater than the - value of since. - If deprecated-since is not specified, then - the event is not deprecated in any version of the containing - &interface;. - - - This event was deprecated in &interface; version - D and above, and should not be sent on - protocol objects of such version. This is informational. - Clients must still be prepared to receive this event - unless otherwise specified. - - - - -
- -
- arg - - - Parent elements: &request;, &event; - - - arg ::= &description;? - - - This element declares one argument for the request or the event. - - - - Required attributes - - - - name="cname" - - - - The name of the argument. &cname-requirements; - The name must be unique within all the arguments of the parent element. - - - - - - type="T" - - - - The type T of the argument datum must - be one of: - - - - int - - 32-bit signed integer. - - - - uint - - 32-bit unsigned integer. - - - - fixed - - Signed 24.8-bit fixed-point value. - - - - string - - - UTF-8 encoded string value, NUL byte terminated. - Interior NUL bytes are not allowed. - - - - - array - - A byte array of arbitrary data. - - - - fd - - A file descriptor. - - The file descriptor must be open and valid on send. - It is not possible to pass a null value. - - - - - new_id - - - Creates a new protocol object. A &request; or an &event; may - have at most one new_id argument. - - - If interface is specified, the new - protocol object shall have the specified &interface;, - and the new object's (interface) version shall be the - version of the object on which the &request; or &event; - is being sent. - - - If interface is not specified, the - &request; shall implicitly have two additional arguments: - A string for an &interface; name, and - a uint for the new object's version. - Leaving the interface unspecified is reserved for special use, - - for example. - - - - An &event; argument must always specify the - new_id interface. - - - - - - object - - Reference to an existing protocol object. - - The attribute interface should be - specified. Otherwise IPC libraries cannot enforce the - interface, and checking the interface falls on user code - and specification text. - - - - - - - - - - Optional attributes - - - - summary="summary" - - - - A short (half a line at most) description. This attribute - should not be used if a &description; is used. - - - - - - interface="iface" - - - - If given, iface must be the - name of some &interface;, and - type of this argument must be either - "object" or "new_id". - This indicates that the existing or new object must have - the interface iface. - Use for other argument types is forbidden. - - - - If an interface from another protocol is used, then this - creates a dependency between the protocols. If an application - generates code for one protocol, then it must also generate - code for all dependencies. Therefore this would not be a - backwards compatible change. - - - - - - - allow-null="true" | "false" - - - - Whether the argument value can be null on send. - Defaults to "false", meaning it is illegal - to send a null value. - Can be used only when type is - "string" or "object". - - - - Even though this attribute can be used to forbid a compositor - from sending a null object as an event argument, an IPC library - implementation may not protect the client from receiving a null - object. This can happen with libwayland-client when the client - has destroyed the protocol object before dispatching an event - that referred to it in an argument. - - - - - - - enum="enum-cname-suffix" - - - - If specified, indicates that the argument value should come from the - &enum; named enum-cname-suffix. If the - enumeration is a bitfield, then type must be - "uint". Otherwise type must - be either "uint" or "int". - - - The name enum-cname-suffix refers to an &enum; - in the same &interface; by default. If it is necessary to refer to an - enumeration from another interface, the interface name can be - given with a period: - enum="iface.enum-cname-suffix" - - - - This attribute alone does not automatically restrict the legal - values for this argument. - If values from outside of the enumeration need to be forbidden, - that must be specified explicitly in the documentation. - - - A common design pattern is to have the server advertise the - supported enumeration or bit values with &event;s and - explicitly forbid clients from using any other values in - requests. This also requires a protocol error code to be - specified with the error &enum; to be raised if a client - uses an illegal value, see - . - - - - - -
- -
- enum - - - Parent elements: &protocol; - - - enum ::= (&description;?, &entry;*) - - - This tag defines an enumeration of integer values. Enumerations are - merely a syntactic construct to give names to arbitrary integer - constants. Each constant is listed as an &entry; with its name. - There are two types of enumerations: regular enumerations and bitfields. - - - Regular enumerations do not use bitfield - attribute, or they set it to "false". - The set of pre-defined values that belong to a regular enumeration is - exactly the set of values listed as &entry; elements after - the protocol object version is taken into account. - See the &entry; attributes since and - deprecated-since. - - - Bitfields set bitfield to - "true". The set of values that belong to a - bitfield enumeration are all the values that can be formed by - the bitwise-or operator from the set of values listed as &entry; - elements like in the regular enumeration. Usually also zero is - implicitly included. - - - All the values in a regular enumeration must be either - signed or unsigned 32-bit integers. All the values in a - bitfield enumeration must be unsigned 32-bit integers. - - - - Required attributes - - - - name="cname-suffix" - - - - The name of the enumeration. &cname-suffix-requirements; - The name must be unique within all enumerations in the containing - &interface;. The name is used as the namespace for all the - contained &entry; elements. - - - - - - - Optional attributes - - - - since="S" - - - - S must be an integer greater than zero. - If since is not specified, - since="1" is assumed. - - - This enumeration was added in &interface; version - S. The enumeration does not exist if the - protocol object has a bound version smaller than - S. - - - - - - bitfield="true" | "false" - - - - Specifies if this enumeration is a bitfield. - Defaults to "false". - - - - -
- -
- entry - - - Parent elements: &enum; - - - entry ::= &description;? - - - Defines a name for an integer constant and makes it part of the - set of values of the containing enumeration. - - - - Required attributes - - - - name="cname-suffix" - - - - The name of a value in an enumeration. &cname-suffix-requirements; - The name must be unique within all entry elements in the containing - &enum;. - - - - - - value="V" - - - - An integer value. - The value can be given in decimal, hexadecimal, or octal - representation. - - - - - - - Optional attributes - - - - summary="summary" - - - - A short (half a line at most) description. This attribute - should not be used if a &description; is used. - - - - - - since="S" - - - - S must be an integer greater than zero. - If since is not specified, - since="1" is assumed. - - - This value was added in &interface; version - S. - - - - - - deprecated-since="D" - - - - D must be an integer greater than the - value of since. - If deprecated-since is not specified, then - the value is not deprecated in any version of the containing - &interface;. - - - This value was removed in &interface; version - D. This does not make the value - automatically illegal to use, see - attribute - enum. - - - - -
-
-
diff --git a/doc/publican/Protocol.xml b/doc/publican/Protocol.xml deleted file mode 100644 index e4087e9f..00000000 --- a/doc/publican/Protocol.xml +++ /dev/null @@ -1,592 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - Wayland Protocol and Model of Operation -
- Basic Principles - - The Wayland protocol is an asynchronous object oriented protocol. All - requests are method invocations on some object. The requests include - an object ID that uniquely identifies an object on the server. Each - object implements an interface and the requests include an opcode that - identifies which method in the interface to invoke. - - - The protocol is message-based. A message sent by a client to the server - is called request. A message from the server to a client is called event. - A message has a number of arguments, each of which has a certain type (see - for a list of argument types). - - - Additionally, the protocol can specify enums which associate - names to specific numeric enumeration values. These are primarily just - descriptive in nature: at the wire format level enums are just integers. - But they also serve a secondary purpose to enhance type safety or - otherwise add context for use in language bindings or other such code. - This latter usage is only supported so long as code written before these - attributes were introduced still works after; in other words, adding an - enum should not break API, otherwise it puts backwards compatibility at - risk. - - - enums can be defined as just a set of integers, or as - bitfields. This is specified via the bitfield boolean - attribute in the enum definition. If this attribute is true, - the enum is intended to be accessed primarily using bitwise operations, - for example when arbitrarily many choices of the enum can be ORed - together; if it is false, or the attribute is omitted, then the enum - arguments are a just a sequence of numerical values. - - - The enum attribute can be used on either uint - or int arguments, however if the enum is - defined as a bitfield, it can only be used on - uint args. - - - The server sends back events to the client, each event is emitted from - an object. Events can be error conditions. The event includes the - object ID and the event opcode, from which the client can determine - the type of event. Events are generated both in response to requests - (in which case the request and the event constitutes a round trip) or - spontaneously when the server state changes. - - - - - - State is broadcast on connect, events are sent - out when state changes. Clients must listen for - these changes and cache the state. - There is no need (or mechanism) to query server state. - - - - - The server will broadcast the presence of a number of global objects, - which in turn will broadcast their current state. - - - - -
-
- Code Generation - - The interfaces, requests and events are defined in - protocol/wayland.xml. - This xml is used to generate the function prototypes that can be used by - clients and compositors. - - - The protocol entry points are generated as inline functions which just - wrap the wl_proxy_* functions. The inline functions aren't - part of the library ABI and language bindings should generate their - own stubs for the protocol entry points from the xml. - -
-
- Wire Format - - The protocol is sent over a UNIX domain stream socket, where the endpoint - usually is named wayland-0 - (although it can be changed via WAYLAND_DISPLAY - in the environment). Beginning in Wayland 1.15, implementations can - optionally support server socket endpoints located at arbitrary - locations in the filesystem by setting WAYLAND_DISPLAY - to the absolute path at which the server endpoint listens. The socket may - also be provided through file descriptor inheritance, in which case - WAYLAND_SOCKET is set. - - - Every message is structured as 32-bit words; values are represented in the - host's byte-order. The message header has 2 words in it: - - - - The first word is the sender's object ID (32-bit). - - - - - The second has 2 parts of 16-bit. The upper 16-bits are the message - size in bytes, starting at the header (i.e. it has a minimum value of 8).The lower is the request/event opcode. - - - - The payload describes the request/event arguments. Every argument is always - aligned to 32-bits. Where padding is required, the value of padding bytes is - undefined. There is no prefix that describes the type, but it is - inferred implicitly from the xml specification. - - - - The representation of argument types are as follows: - - - int - uint - - - The value is the 32-bit value of the signed/unsigned - int. - - - - - fixed - - - Signed 24.8 decimal numbers. It is a signed decimal type which - offers a sign bit, 23 bits of integer precision and 8 bits of - decimal precision. This is exposed as an opaque struct with - conversion helpers to and from double and int on the C API side. - - - - - string - - - Starts with an unsigned 32-bit length (including null terminator), - followed by the UTF-8 encoded string contents, including - terminating null byte, then padding to a 32-bit boundary. A null - value is represented with a length of 0. Interior null bytes are - not permitted. - - - - - object - - - 32-bit object ID. A null value is represented with an ID of 0. - - - - - new_id - - - The 32-bit object ID. Generally, the interface used for the new - object is inferred from the xml, but in the case where it's not - specified, a new_id is preceded by a string specifying - the interface name, and a uint specifying the version. - - - - - array - - - Starts with 32-bit array size in bytes, followed by the array - contents verbatim, and finally padding to a 32-bit boundary. - - - - - fd - - - The file descriptor is not stored in the message buffer, but in - the ancillary data of the UNIX domain socket message (msg_control). - - - - - - - The protocol does not specify the exact position of the ancillary data - in the stream, except that the order of file descriptors is the same as - the order of messages and fd arguments within messages on - the wire. - - - In particular, it means that any byte of the stream, even the message - header, may carry the ancillary data with file descriptors. - - - Clients and compositors should queue incoming data until they have - whole messages to process, as file descriptors may arrive earlier - or later than the corresponding data bytes. - -
- -
- Versioning - - Every interface is versioned and every protocol object implements a - particular version of its interface. For global objects, the maximum - version supported by the server is advertised with the global and the - actual version of the created protocol object is determined by the - version argument passed to wl_registry.bind(). For objects that are - not globals, their version is inferred from the object that created - them. - - - In order to keep things sane, this has a few implications for - interface versions: - - - - The object creation hierarchy must be a tree. Otherwise, - inferring object versions from the parent object becomes a much - more difficult to properly track. - - - - - When the version of an interface increases, so does the version - of its parent (recursively until you get to a global interface) - - - - - A global interface's version number acts like a counter for all - of its child interfaces. Whenever a child interface gets - modified, the global parent's interface version number also - increases (see above). The child interface then takes on the - same version number as the new version of its parent global - interface. - - - - - - To illustrate the above, consider the wl_compositor interface. It - has two children, wl_surface and wl_region. As of wayland version - 1.2, wl_surface and wl_compositor are both at version 3. If - something is added to the wl_region interface, both wl_region and - wl_compositor will get bumpped to version 4. If, afterwards, - wl_surface is changed, both wl_compositor and wl_surface will be at - version 5. In this way the global interface version is used as a - sort of "counter" for all of its child interfaces. This makes it - very simple to know the version of the child given the version of its - parent. The child is at the highest possible interface version that - is less than or equal to its parent's version. - - - It is worth noting a particular exception to the above versioning - scheme. The wl_display (and, by extension, wl_registry) interface - cannot change because it is the core protocol object and its version - is never advertised nor is there a mechanism to request a different - version. - -
-
- Connect Time - - There is no fixed connection setup information, the server emits - multiple events at connect time, to indicate the presence and - properties of global objects: outputs, compositor, input devices. - -
-
- Security and Authentication - - - - - mostly about access to underlying buffers, need new drm auth - mechanism (the grant-to ioctl idea), need to check the cmd stream? - - - - - getting the server socket depends on the compositor type, could - be a system wide name, through fd passing on the session dbus. - or the client is forked by the compositor and the fd is - already opened. - - - - -
-
- Creating Objects - - Each object has a unique ID. The IDs are allocated by the entity - creating the object (either client or server). IDs allocated by the - client are in the range [1, 0xfeffffff] while IDs allocated by the - server are in the range [0xff000000, 0xffffffff]. The 0 ID is - reserved to represent a null or non-existent object. - - For efficiency purposes, the IDs are densely packed in the sense that - the ID N will not be used until N-1 has been used. This ordering is - not merely a guideline, but a strict requirement, and there are - implementations of the protocol that rigorously enforce this rule, - including the ubiquitous libwayland. - -
-
- Compositor - - The compositor is a global object, advertised at connect time. - - - See for the - protocol description. - -
-
- Surfaces - - A surface manages a rectangular grid of pixels that clients create - for displaying their content to the screen. Clients don't know - the global position of their surfaces, and cannot access other - clients' surfaces. - - - Once the client has finished writing pixels, it 'commits' the - buffer; this permits the compositor to access the buffer and read - the pixels. When the compositor is finished, it releases the - buffer back to the client. - - - See for the protocol - description. - -
-
- Input - - A seat represents a group of input devices including mice, - keyboards and touchscreens. It has a keyboard and pointer - focus. Seats are global objects. Pointer events are delivered - in surface-local coordinates. - - - The compositor maintains an implicit grab when a button is - pressed, to ensure that the corresponding button release - event gets delivered to the same surface. But there is no way - for clients to take an explicit grab. Instead, surfaces can - be mapped as 'popup', which combines transient window semantics - with a pointer grab. - - - To avoid race conditions, input events that are likely to - trigger further requests (such as button presses, key events, - pointer motions) carry serial numbers, and requests such as - wl_surface.set_popup require that the serial number of the - triggering event is specified. The server maintains a - monotonically increasing counter for these serial numbers. - - - Input events also carry timestamps with millisecond granularity. - Their base is undefined, so they can't be compared against - system time (as obtained with clock_gettime or gettimeofday). - They can be compared with each other though, and for instance - be used to identify sequences of button presses as double - or triple clicks. - - - See for the - protocol description. - - - Talk about: - - - - - keyboard map, change events - - - - - xkb on Wayland - - - - - multi pointer Wayland - - - - - - A surface can change the pointer image when the surface is the pointer - focus of the input device. Wayland doesn't automatically change the - pointer image when a pointer enters a surface, but expects the - application to set the cursor it wants in response to the pointer - focus and motion events. The rationale is that a client has to manage - changing pointer images for UI elements within the surface in response - to motion events anyway, so we'll make that the only mechanism for - setting or changing the pointer image. If the server receives a request - to set the pointer image after the surface loses pointer focus, the - request is ignored. To the client this will look like it successfully - set the pointer image. - - - Setting the pointer image to NULL causes the cursor to be hidden. - - - The compositor will revert the pointer image back to a default image - when no surface has the pointer focus for that device. - - - What if the pointer moves from one window which has set a special - pointer image to a surface that doesn't set an image in response to - the motion event? The new surface will be stuck with the special - pointer image. We can't just revert the pointer image on leaving a - surface, since if we immediately enter a surface that sets a different - image, the image will flicker. If a client does not set a pointer image - when the pointer enters a surface, the pointer stays with the image set - by the last surface that changed it, possibly even hidden. Such a client - is likely just broken. - -
-
- Output - - An output is a global object, advertised at connect time or as it - comes and goes. - - - See for the protocol - description. - - - - - - - laid out in a big (compositor) coordinate system - - - - - basically xrandr over Wayland - - - - - geometry needs position in compositor coordinate system - - - - - events to advertise available modes, requests to move and change - modes - - - -
-
- Data sharing between clients - - The Wayland protocol provides clients a mechanism for sharing - data that allows the implementation of copy-paste and - drag-and-drop. The client providing the data creates a - wl_data_source object and the clients - obtaining the data will see it as wl_data_offer - object. This interface allows the clients to agree on a mutually - supported mime type and transfer the data via a file descriptor - that is passed through the protocol. - - - The next section explains the negotiation between data source and - data offer objects. - explains how these objects are created and passed to different - clients using the wl_data_device interface - that implements copy-paste and drag-and-drop support. - - - See , - , - and - for - protocol descriptions. - - - MIME is defined in RFC's 2045-2049. A - - registry of MIME types is maintained by the Internet Assigned - Numbers Authority (IANA). - -
- Data negotiation - - A client providing data to other clients will create a wl_data_source - object and advertise the mime types for the formats it supports for - that data through the wl_data_source.offer - request. On the receiving end, the data offer object will generate one - wl_data_offer.offer event for each supported mime - type. - - - The actual data transfer happens when the receiving client sends a - wl_data_offer.receive request. This request takes - a mime type and a file descriptor as arguments. This request will generate a - wl_data_source.send event on the sending client - with the same arguments, and the latter client is expected to write its - data to the given file descriptor using the chosen mime type. - -
-
- Data devices - - Data devices glue data sources and offers together. A data device is - associated with a wl_seat and is obtained by the clients using the - wl_data_device_manager factory object, which is also responsible for - creating data sources. - - - Clients are informed of new data offers through the - wl_data_device.data_offer event. After this - event is generated the data offer will advertise the available mime - types. New data offers are introduced prior to their use for - copy-paste or drag-and-drop. - -
- Selection - - Each data device has a selection data source. Clients create a data - source object using the device manager and may set it as the - current selection for a given data device. Whenever the current - selection changes, the client with keyboard focus receives a - wl_data_device.selection event. This event is - also generated on a client immediately before it receives keyboard - focus. - - - The data offer is introduced with - wl_data_device.data_offer event before the - selection event. - -
-
- Drag and Drop - - A drag-and-drop operation is started using the - wl_data_device.start_drag request. This - requests causes a pointer grab that will generate enter, motion and - leave events on the data device. A data source is supplied as - argument to start_drag, and data offers associated with it are - supplied to clients surfaces under the pointer in the - wl_data_device.enter event. The data offer - is introduced to the client prior to the enter event with the - wl_data_device.data_offer event. - - - Clients are expected to provide feedback to the data sending client - by calling the wl_data_offer.accept request with - a mime type it accepts. If none of the advertised mime types is - supported by the receiving client, it should supply NULL to the - accept request. The accept request causes the sending client to - receive a wl_data_source.target event with the - chosen mime type. - - - When the drag ends, the receiving client receives a - wl_data_device.drop event at which it is expected - to transfer the data using the - wl_data_offer.receive request. - -
-
-
-
diff --git a/doc/publican/Wayland.xml b/doc/publican/Wayland.xml index 049a35f9..4c3695de 100644 --- a/doc/publican/Wayland.xml +++ b/doc/publican/Wayland.xml @@ -6,14 +6,6 @@ - - - - - - - - diff --git a/doc/publican/Xwayland.xml b/doc/publican/Xwayland.xml deleted file mode 100644 index cc5a73dd..00000000 --- a/doc/publican/Xwayland.xml +++ /dev/null @@ -1,168 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - X11 Application Support -
- Introduction - - Being able to run existing X11 applications is crucial for the adoption - of Wayland, especially on desktops, as there will always be X11 - applications that have not been or cannot be converted into Wayland - applications, and throwing them all away would be prohibitive. - Therefore a Wayland compositor often needs to support running X11 - applications. - - - X11 and Wayland are different enough that there is no "simple" way to - translate between them. Most of X11 is uninteresting to a Wayland - compositor. That, combined with the gigantic implementation effort needed - to support X11, makes it intractable to just write X11 support directly in - a Wayland compositor. The implementation would be nothing short of a - real X11 server. - - - Therefore, Wayland compositors should use Xwayland, the X11 server that - lives in the Xorg server source code repository and shares most of the - implementation with the Xorg server. Xwayland is a complete X11 server, - just like Xorg is, but instead of driving the displays and opening input - devices, it acts as a Wayland client. The rest of this chapter talks - about how Xwayland works. - - - For integration and architecture reasons, while Xwayland is a Wayland - client of the Wayland compositor, the Wayland compositor is an X11 client - of Xwayland. This circular dependency requires special care from the - Wayland compositor. - -
-
- Two Modes for Foreign Windows - - In general, windows from a foreign window system can be presented in one - of two ways: rootless and rootful (not rootless). - - - In rootful mode, the foreign window system as a whole is represented as a - window (or more) of its own. You have a native window, inside which all - the foreign windows are. The advantage of this approach in Xwayland's - case is that you can run your favourite X11 window manager to manage your - X11 applications. The disadvantage is that the foreign windows do not - integrate with the native desktop. Therefore this mode is not usually - used. - - - In rootless mode, each foreign window is a first-class resident among the - native windows. Foreign windows are not confined inside a native window - but act as if they were native windows. The advantage is that one can - freely stack and mix native and foreign windows, which is not possible in - rootful mode. The disadvantage is that this mode is harder to implement - and fundamental differences in window systems may prevent some things - from working. With rootless Xwayland, the Wayland compositor must take - the role as the X11 window manager, and one cannot use any other X11 - window manager in its place. - - - This chapter concentrates on the rootless mode, and ignores the rootful - mode. - -
-
- Architecture - - A Wayland compositor usually takes care of launching Xwayland. - Xwayland works in cooperation with a Wayland compositor as follows: - -
- Xwayland architecture diagram - - - - - -
- - An X11 application connects to Xwayland just like it would connect to any - X server. Xwayland processes all the X11 requests. On the other end, - Xwayland is a Wayland client that connects to the Wayland compositor. - - - The X11 window manager (XWM) is an integral part of the Wayland - compositor. XWM uses the usual X11 window management protocol to manage - all X11 windows in Xwayland. Most importantly, XWM acts as a bridge - between Xwayland window state and the Wayland compositor's window manager - (WWM). This way WWM can manage all windows, both native Wayland and X11 - (Xwayland) windows. This is very important for a coherent user - experience. - - - Since Xwayland uses Wayland for input and output, it does not have any - use for the device drivers that Xorg uses. None of the xf86-video-* or - xf86-input-* modules are used. There also is no configuration file for - the Xwayland server. For optional hardware accelerated rendering, - Xwayland uses GLAMOR. - - - A Wayland compositor usually spawns only one Xwayland instance. This is - because many X11 applications assume they can communicate with other X11 - applications through the X server, and this requires a shared X server - instance. This also means that Xwayland does not protect nor isolate X11 - clients from each other, unless the Wayland compositor specifically - chooses to break the X11 client intercommunications by spawning - application specific Xwayland instances. X11 clients are naturally - isolated from Wayland clients. - - - Xwayland compatibility compared to a native X server will probably never - reach 100%. Desktop environment (DE) components, specifically X11 window - managers, are practically never supported. An X11 window manager would - not know about native Wayland windows, so it could manage only X11 - windows. On the other hand, there must be an XWM that reserves the - exclusive window manager role so that the Wayland compositor could show - the X11 windows appropriately. For other DE components, like pagers and - panels, adding the necessary interfaces to support them in WWM through XWM - is often considered not worthwhile. - -
-
- X Window Manager (XWM) - - From the X11 point of view, the X window manager (XWM) living inside a - Wayland compositor is just like any other window manager. The difference - is mostly in which process it resides in, and the few extra conventions - in the X11 protocol to support Wayland window management (WWM) - specifically. - - - There are two separate asynchronous communication channels between - Xwayland and a Wayland compositor: one uses the Wayland protocol, and the - other one, solely for XWM, uses X11 protocol. This setting demands great - care from the XWM implementation to avoid (random) deadlocks with - Xwayland. It is often nearly impossible to prove that synchronous or - blocking X11 calls from XWM cannot cause a deadlock, and therefore it is - strongly recommended to make all X11 communications asynchronous. All - Wayland communications are already asynchronous by design. - -
- Window identification - - In Xwayland, an X11 window may have a corresponding wl_surface object - in Wayland. The wl_surface object is used for input and output: it is - referenced by input events and used to provide the X11 window content - to the Wayland compositor. The X11 window and the wl_surface live in - different protocol streams, and they need to be matched for XWM to do - its job. - - - When Xwayland creates a wl_surface on Wayland, it will also send an X11 - ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying - the wl_surface Wayland object ID as the first 32-bit data element. This - is how XWM can associate a wl_surface with an X11 window. Note that - the request to create a wl_surface and the ID message may arrive in any - order in the Wayland compositor. - -
-
-
diff --git a/doc/publican/html/images/content-updates/content-update-legend.png b/doc/publican/html/images/content-updates/content-update-legend.png deleted file mode 100644 index 84f12e76aefa65bdc7fe98fb81bc168fdbb14416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15946 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
L23 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/content-updates/meson.build b/doc/publican/html/images/content-updates/meson.build deleted file mode 100644 index 850e81ff..00000000 --- a/doc/publican/html/images/content-updates/meson.build +++ /dev/null @@ -1,35 +0,0 @@ -foreach src : files([ - 'simple-desynchronized-state-1.png', - 'simple-desynchronized-state-2.png', - 'simple-desynchronized-state-3.png', - 'simple-desynchronized-state-4.png', - 'simple-desynchronized-state-5.png', - 'simple-desynchronized-state-6.png', - 'simple-synchronized-state-1.png', - 'simple-synchronized-state-2.png', - 'simple-synchronized-state-3.png', - 'simple-synchronized-state-4.png', - 'simple-synchronized-state-5.png', - 'sync-subsurf-case1-1.png', - 'sync-subsurf-case1-2.png', - 'sync-subsurf-case1-3.png', - 'sync-subsurf-case1-4.png', - 'sync-subsurf-case1-5.png', - 'sync-subsurf-case2-1.png', - 'sync-subsurf-case2-2.png', - 'sync-subsurf-case2-3.png', - 'sync-to-desync-subsurf-1.png', - 'sync-to-desync-subsurf-2.png', - 'sync-to-desync-subsurf-3.png', - 'sync-to-desync-transition-1.png', - 'sync-to-desync-transition-2.png', - 'sync-to-desync-transition-3.png', - 'content-update-legend.png', -]) - name = fs.name(src) - publican_inputs += fs.copyfile( - name, - install: true, - install_dir: publican_install_prefix + '/html/images/content-updates', - ) -endforeach diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-1.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-1.png deleted file mode 100644 index d319ac2579f10e583afc13d6dd3bd467dc769ef1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2037 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMnSp_Ub;foOrI73q~wMMX|k)80QKB(pTCu)dZHZ?Wn<>j@sw466@Uhl?Z+lzNb!|VqsyCl9I~J&5enPdH??XrcIkTIXT(b*cL2U(7JrLp{?uUGfx^8Z1(o{ zK6&!wuV24{f`ZN#C@6U3$Po(*i?Fb;moHyVnKC6JB4Ypk{rdX)*4EZ)YHAlRUi9+v5)l!R zmX?;0kufwhESa=;)BRstwrttEckj%ZGnX!1`r^fl*RNkMTC}LCsYyaY!o$O(t*veG z;>Eqay&E=c2nYyhZf;()W=%^=OH@=8D=RB+z<*H&1_s6?Z+91l4pvzY1_lQ95>H=O z_E(GooCY$Np6rcaU|@OS>EaktaqI2fpTWZE5(hrEJ3J7~n9#s-;aV802+ucxa8Ab; ztsmb!y~riFH1x=7*V|oDuB#VqZMS_<`)~PN-i2w+rEF=_pPa0*-`}wNy+Pi-b(P<_ zlo(Kf+0@ok+J{7+F5Kkw-*tmZ>eNuH^{XazHAa6->Hb%F)pYBu)n+lVFMM@MwdYk$ za#ioSlDTh}$HMI!kNljyL1}hwYV8)qsQpI2mv=ekr(}LMO-x>PV^!O-8*`RD3!SOj z+j{TRq-W`ecGeo)5~^OJda6#sL|)kKPQ=>P$#JWr?;hPF&vtx&%hh*2%SwH9?n`Y? zl>L0^z>n!0j@`Ze?EAsx^8;h8_sj3nKGb^e!lkFthm5{g7|dGx?M?A7jl?sx_G_L> z)N5W_d;h|ta%kci#Me6(8nCoSD4gWbDcROS-QwW#``+ z&!7FrBdhM=?qBoLC&Y6)zq6b&(nM34V8K06ppw4+D8!A5A7yVGZnh%2ZGV)v75+4IuQhmy91R&TT16*4sBXSO0eTX3eg$j*rv#<)!BKJL}s`>r|fBeg1I!y+_6=P1?|oc@+hTe785kH;OI#yLQW8s2t&)pU6H8JVj0}v-bPWu34NXIg z46RH|txPPn4GgRd4D?sI>_E|wo1c=IR*9y;$kNKd5TZf)_OuWN1_lkd4JDbmsl_FU jxdjM4W+4WaRwfo!Mivk~d<(y4ft=~->gTe~DWM4f`Yf6v diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-2.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-2.png deleted file mode 100644 index ecd284cd6751882532c29984c00957ebdf323b8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6732 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 b%EZFT$O58=Z{hbWkRv@^{an^LB{Ts5an#hk diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-4.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-4.png deleted file mode 100644 index 83dcc063fac852fc513e3bfeb63a7450462cb454..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7302 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 P1_lOCS3j3^P6&6h2cL4F4((#G6Mqxdx@v7 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 aurjiM=;2%VJ&S>Xfx*+&&t;ucLK6Tuv==A< diff --git a/doc/publican/html/images/content-updates/simple-desynchronized-state-6.png b/doc/publican/html/images/content-updates/simple-desynchronized-state-6.png deleted file mode 100644 index ebb88d8189e24c11c018540d8068380b753031df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmeAS@N?(olHy`uVBq!ia0y~yU_8vg!0?-cnSp^pk&S-_0|SFXvPY0F14ES>14Ba# z1H&%{28M(N=nM^ zmDAW*Sq-$+LPJAOoH#LO&Ybn@*JoyC*4EZ8p4_y3>7?HJ!t2+si;Ih=r>DPt`}Xta z&%wdLJUl#petuW3Tv@SV1rrm~^XJbeO`0SrDXFWg`|;z)fB*h1U%oseBSTwTo1dTm z+_`fL7cRVf`SSPg-y0hn6A}`pPoJ)*r+5GUeH|Sg6&022?Cd2=mIw+89yxNv!ouRq zmoH&qVb0FZFJHc#GG$6cM8y96`}Otp@1NYXf6dIC#IRZ2)juB|x3;!cQ&YQm@#5yq zo4vfeL_|cSrKM$LWDE@rn@TgDU)Z^2%a*-+_s*O-bLrBhFJ8QO{rdHyMT?r6nkp(P zBqSs}JUrUk+7>Tf+}qo`aY3J{ftCOtZ?L!1onsr$?_TEaVCi6Ge0am04I4HD1O!~# zyTZ&+J1;qcmxs&TNay3tgJL2=s)}-jX;F%DQhdDJ@2>A_Zf;()X3eq9^PZmH9_Huz z`_ajZdzMdVDn7bto|L$#y0ZM;;~QOU&E#byUtZd!ucfwi@x&!lnuP`VAD`VODK7Hj z;;u~#`y%|^_<4D*>|gcc!7*b!%`-a|A6z$Ua%)*jOG{K#)WqfzPbaIHT~#}lO}=q> zEei{CWp1Lax#7vJ3t3rN^HU;st(eNi$-&CPVri_maz?wGy~XuIYg80ue?2_0eANMA z1_lPkByV>Yh7ML)4+aJX_7YEDSN2zo0-Odim!9m6U|?Wr@pN$vskrs_?$7X$REYy0 z(~kv4ili9G?>S|_p=+`3tzPb-4ld0{VHrz1mM-#K+Vm`8+l6_qzms-vi?}gQciZ&0 zzrQ^%NnI?Qs$CgSLBoH|3+?~**?rNqSP^bw zqF|wMgsvZRTDaZkJ&|6x z@U~m##SH)BCvH6Q@C;F2YUFqN(9^1-XFdBLYA%13X;R|Z+Bf|MOa3F3xjIHiXKO8g zEm^c|-c-xS*%jX`pI^G5`_n47>QixBTl%rSIX3?1&(Ha2y63^6?u-}HB3)Na4K17* zyVffG-JUBuXWcq+bf&TGyLOWj-*bOnFs+T&_}VR|e{tz)mnV}R?eVTvHYtgBZWUX? zH|;go#M56sY5#f6D78yxUr}hxlECnA^RoF*{Uug)Z5ed;8nAu!*ltGu@x{tWQ+h zde6@}nyJP=Sq?df?4)kFL&J@GL;A5j3*@V>qXsqxFM)yc%fkKZ`D?j9>12FvvYC9> z24M&^@cX1~QZmBI`aIrkcv$&Uc~W{=*4+A*wmj*ju8VDDm6N-bRRepcblth&;vB72 zvge3eg|Pa|l!==6LO55uJ4b&iz4hhEa~|IFJ*xa=cPoT>b7zJwiHa1Re)H<8;%Dc) z=k1!=cI?TSe!UC3T7&jyd=!e^)zfBX8j|7oDq-ikAM4xpcwfu>ICb?SrQTh;c4hW@ z^oCu$FmJ1rX5{jzuV-)7*|jjn{FJWj_E)*Gvb>VUCMD5pDvKXZdl5GA+P2)=x1(J1 zu1~qtBZ=XyZx=7X0xZ74*7zCg-y6HxFaiiwfZ1aK|KHl$7ts^a9cLfkor07;p=Q0< z_vQALuY7_huN|vjfB8b~yzS1~w(tE`?)R?FtoUxb`~BYc9y`zdF1P=nz$^P{f}M`i z(pC39O4|kfev#a7e{pWX`N{saf6r__fANCs%QoKg&)?bB9j@&ZchZ05{jzPgkbe8O z*V-l}?zl=SRXuKYG-`Tl*PQ+pJduwW6XB^u8b*|XEcD|Q;6Tk0H zx&PK`$NL-WA6CDw|L{;zYS&{Isk$#84>G%R*G;kz`4wWnc%k(!>AHI#Tl?PJxLRy_ z_k;Iet%)96RdP{kVo554k%5t!u7RPhp=pSbp_PfLm5HUc zfq|8Qf&MC&9Vi-d^HVa@D$z6;Sz4JILNo+h&oE$MV9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/content-updates/simple-synchronized-state-1.png b/doc/publican/html/images/content-updates/simple-synchronized-state-1.png deleted file mode 100644 index be101446104f7798a8d39f8edb0dbd1bdec3e24b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2117 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 diff --git a/doc/publican/html/images/content-updates/simple-synchronized-state-4.png b/doc/publican/html/images/content-updates/simple-synchronized-state-4.png deleted file mode 100644 index e8b9b3db323541330fcfecce76c831f62c97698a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17710 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 diff --git a/doc/publican/html/images/content-updates/simple-synchronized.drawio b/doc/publican/html/images/content-updates/simple-synchronized.drawio deleted file mode 100644 index a478ae02..00000000 --- a/doc/publican/html/images/content-updates/simple-synchronized.drawio +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-1.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-1.png deleted file mode 100644 index 1f7ff8e42b9783c3ee6fb54c66828ec033cdd13d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26995 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 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-2.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-2.png deleted file mode 100644 index 6839b679990902c4ae4a4a5e092244d74b853ee7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27535 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 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-3.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-3.png deleted file mode 100644 index 9810a028186cba6b1578637834e7a5842fef9aaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22771 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 BZ`c3; diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-4.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-4.png deleted file mode 100644 index bf3c04bcf0fc93b0661a475aaa02b7f7821bb734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22017 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 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1-5.png b/doc/publican/html/images/content-updates/sync-subsurf-case1-5.png deleted file mode 100644 index 1b2ebc3b1dd53819002152d9f8d77413bdefec79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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�`%*@I>{#6$H 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 M)78&qol`;+0Ak{N+5i9m diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case1.drawio b/doc/publican/html/images/content-updates/sync-subsurf-case1.drawio deleted file mode 100644 index 385c6fd7..00000000 --- a/doc/publican/html/images/content-updates/sync-subsurf-case1.drawio +++ /dev/null @@ -1,500 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2-1.png b/doc/publican/html/images/content-updates/sync-subsurf-case2-1.png deleted file mode 100644 index 25408cfcc4290ab9bb830824518b0a46cd1bd789..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26210 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 bpI!d8_sP5e^D`M37#KWV{an^LB{Ts5gHhMH diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2-2.png b/doc/publican/html/images/content-updates/sync-subsurf-case2-2.png deleted file mode 100644 index 63ea066cf2e69d339936f24f6900908606bbca55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25821 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ℜ7d?Pq?wI(mT9(FY?nw;T~il_FJxnl)A^@` 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 diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2-3.png b/doc/publican/html/images/content-updates/sync-subsurf-case2-3.png deleted file mode 100644 index 3948988d51cf3f2f671bdfe53e81f9b6d1ba1ec3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10069 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 I&MBb@0KaK6BLDyZ diff --git a/doc/publican/html/images/content-updates/sync-subsurf-case2.drawio b/doc/publican/html/images/content-updates/sync-subsurf-case2.drawio deleted file mode 100644 index c1eaff66..00000000 --- a/doc/publican/html/images/content-updates/sync-subsurf-case2.drawio +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf-1.png b/doc/publican/html/images/content-updates/sync-to-desync-subsurf-1.png deleted file mode 100644 index 3a56f260a12df2c07b0d95f2bedd518f2d4cb061..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18621 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ξ5oqLG$`A_9_05Zk(PP|Jd=jbcma%tD;e3l+TWJ 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 P0|SGntDnm{r-UW|Uh!wq diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf-2.png b/doc/publican/html/images/content-updates/sync-to-desync-subsurf-2.png deleted file mode 100644 index 9cb6210c6594e2979d7177df8865866b098eddfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18069 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 b{rCNsD%r!pz`)??>gTe~DWM4fMP1|1 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf-3.png b/doc/publican/html/images/content-updates/sync-to-desync-subsurf-3.png deleted file mode 100644 index 34bf7475ecf227af341f314e02e4a670861ce849..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19371 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 diff --git a/doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio b/doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio deleted file mode 100644 index 7a72e0f6..00000000 --- a/doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio +++ /dev/null @@ -1,223 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/content-updates/sync-to-desync-transition-1.png b/doc/publican/html/images/content-updates/sync-to-desync-transition-1.png deleted file mode 100644 index cd69f3c34da5cf101bd2d0703225b7e695e1c03b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9299 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 E0Lwg-GXMYp diff --git a/doc/publican/html/images/content-updates/sync-to-desync-transition-2.png b/doc/publican/html/images/content-updates/sync-to-desync-transition-2.png deleted file mode 100644 index 677a0cdb1b182a19442633be3597337c6c869de9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15177 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 A_5c6? diff --git a/doc/publican/html/images/content-updates/sync-to-desync-transition.drawio b/doc/publican/html/images/content-updates/sync-to-desync-transition.drawio deleted file mode 100644 index 9843acb6..00000000 --- a/doc/publican/html/images/content-updates/sync-to-desync-transition.drawio +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/icon.svg b/doc/publican/html/images/icon.svg deleted file mode 100644 index b2f16d0f..00000000 --- a/doc/publican/html/images/icon.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/doc/publican/html/images/meson.build b/doc/publican/html/images/meson.build deleted file mode 100644 index c06e9be8..00000000 --- a/doc/publican/html/images/meson.build +++ /dev/null @@ -1,37 +0,0 @@ -foreach src : files([ - 'icon.svg', - 'wayland.png', -]) - name = fs.name(src) - publican_inputs += fs.copyfile( - name, - install: true, - install_dir: publican_install_prefix + '/html/images', - ) -endforeach - -subdir('content-updates') - -foreach src : files([ - 'wayland-architecture.gv', - 'x-architecture.gv', -]) - input = fs.name(src) - output = fs.stem(src) + '.png' - - publican_inputs += custom_target( - input + '.png', - command: [ dot, '-Tpng', '-o@OUTPUT@', '@INPUT@' ], - input: input, - output: output, - install: true, - install_dir: publican_install_prefix + '/html/images', - ) - - publican_image_maps += custom_target( - input + '.map', - command: [ dot, '-Tcmapx_np', '-o@OUTPUT@', '@INPUT@' ], - input: input, - output: fs.stem(src) + '.map', - ) -endforeach diff --git a/doc/publican/html/images/wayland-architecture.gv b/doc/publican/html/images/wayland-architecture.gv deleted file mode 100644 index f2c35075..00000000 --- a/doc/publican/html/images/wayland-architecture.gv +++ /dev/null @@ -1,36 +0,0 @@ -digraph arch_wayland { - edge[ - fontname="DejaVu Sans", - dir="both", - arrowtail="dot", - arrowsize=.5, - fontname="DejaVu Sans", - fontsize="18", - ] - - node[ - color=none, - margin=0, - fontname="DejaVu Sans", - fontsize="18", - ] - - c1 [label=<
Wayland Client
>, URL="#c1"] - c2 [label=<
Wayland Client
>, URL="#c2"] - - comp [tooltip="Wayland Compositor", label=<

Wayland
Compositor

>, URL="#comp"] - - impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] - - c1 -> comp [taillabel="③", labeldistance=2.5, URL="#step_3"]; - c2 -> comp; - - comp -> c1 [label="②", URL="#step_2"]; - comp -> c2; - - comp -> impl [xlabel = "④", URL="#step_4"]; - comp -> impl [style = invis, label=" "]; - impl -> comp [xlabel = "①", URL="#step_1"]; - - c1 -> c2 [style=invis]; -} diff --git a/doc/publican/html/images/x-architecture.gv b/doc/publican/html/images/x-architecture.gv deleted file mode 100644 index b223d1dc..00000000 --- a/doc/publican/html/images/x-architecture.gv +++ /dev/null @@ -1,53 +0,0 @@ -digraph arch_x { - edge[ - fontname="DejaVu Sans", - dir="both", - arrowtail="dot", - arrowsize=.5, - fontname="DejaVu Sans", - fontsize="18", - ] - - node[ - shape="none", - color=none, - margin=0, - fontname="DejaVu Sans", - fontsize="18", - ] - - { - rank=same; - c1 [label=<
X Client
>, URL="#c1"] - c3 [label=<
X Client
>, URL="#c3"] - } - c2 [label=<
X Client
>, URL="#c2"] - - { - rank=same; - xserver [tooltip="X Server", label=<

X Server

>, URL="#xserver"] - comp [tooltip="Compositor", label=<

Compositor

>, URL="#comp"] - } - - impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] - - c1 -> xserver [taillabel="③", labeldistance=2, URL="#step_3"]; - c2 -> xserver; - c3 -> xserver; - - xserver -> c1 [taillabel="②", labeldistance=2, URL="#step_2"]; - xserver -> c2; - xserver -> c3; - - xserver -> impl [taillabel="⑥", labeldistance=1.75, URL="#step_6"]; - xserver -> impl [style=invis, label=" "]; - impl -> xserver [taillabel="①", labeldistance=1.75, URL="#step_1"]; - - xserver -> comp [style=invis]; - xserver -> comp [taillabel="④", labeldistance=1.75, labelangle=-45, URL="#step_4"]; - comp -> xserver [taillabel="⑤", URL="#step_5"]; - comp -> xserver [style=invis] - - c1 -> c2 [style=invis]; - c3 -> c2 [style=invis]; - } diff --git a/doc/publican/html/images/xwayland-architecture.png b/doc/publican/html/images/xwayland-architecture.png deleted file mode 100644 index f24dc1837f2e190c9d38719420a844aeb5997efa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7611 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 diff --git a/doc/publican/meson.build b/doc/publican/meson.build index a572b0eb..1b3965d5 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -12,14 +12,8 @@ foreach src : files([ 'Book_Info.xml', 'Author_Group.xml', 'Foreword.xml', - 'Protocol.xml', - 'Xwayland.xml', - 'Compositors.xml', - 'Content_Updates.xml', - 'Color.xml', 'Client.xml', 'Server.xml', - 'Message_XML.xml', ]) name = fs.name(src) publican_inputs += fs.copyfile(name) @@ -72,27 +66,6 @@ publican_inputs += custom_target( ) subdir('html/css') -subdir('html/images') - -foreach src : files([ - 'Architecture.xml', - 'Introduction.xml' -]) - name = fs.name(src) - publican_inputs += custom_target( - name, - command: [ - xsltproc, - '-o', '@OUTPUT@', - '--stringparam', 'basedir', meson.current_build_dir() / 'html', - merge_mapcoords_xsl, - '@INPUT@', - ], - input: src, - output: [name], - depends: publican_image_maps, - ) -endforeach skip_validation = '--skip-validation' if get_option('docbook_validation') From bc7a55a134b52fa94ea7c4e386858a31b03b8e95 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 31 Jan 2026 12:01:06 +0100 Subject: [PATCH 1128/1152] doc: reword docbook foreword to capture new scope Signed-off-by: Julian Orth --- doc/publican/Foreword.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/publican/Foreword.xml b/doc/publican/Foreword.xml index 97908356..080ed711 100644 --- a/doc/publican/Foreword.xml +++ b/doc/publican/Foreword.xml @@ -9,8 +9,7 @@ Preface - This document describes the (i) Wayland architecture, (ii) Wayland model of - operation and (iii) its library API. Also, the Wayland protocol specification is shown + This document describes its library API. Also, the Wayland protocol specification is shown in the Appendix. This document is aimed primarily at Wayland developers and those looking to program with it; it does not cover application development. From 4897da68e622cc1c9a713411c5200b661a59b7f5 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 2 Feb 2026 11:25:59 +0100 Subject: [PATCH 1129/1152] doc: turn captions into third-level headers in book Signed-off-by: Julian Orth --- doc/book/src/Content_Updates.md | 162 ++++++++++++++++---------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/doc/book/src/Content_Updates.md b/doc/book/src/Content_Updates.md index 91d290f0..5b55bab0 100644 --- a/doc/book/src/Content_Updates.md +++ b/doc/book/src/Content_Updates.md @@ -73,142 +73,142 @@ In all the examples below, the surface T1 refers to a toplevel surface, SS1 refers to a sub-surface which is a child of T1, and SS2 refers to a sub-surface which is a child of SS1. -**Legend** +### Legend ![](images/content-updates/content-update-legend.png) -**Simple Desynchronized Case** +### Simple Desynchronized Case -![](images/content-updates/simple-desynchronized-state-1.png) +1. SS2 is effectively desynchronized and commits. This results in the + desynchronized content update (DCU) _1_. -SS2 is effectively desynchronized and commits. This results in the -desynchronized content update (DCU) _1_. + ![](images/content-updates/simple-desynchronized-state-1.png) -![](images/content-updates/simple-desynchronized-state-2.png) +2. DCU _1_ is a candidate, and the candidate DAG reachable from DCU _1_ is only DCU + _1_ itself. DCU _1_ and thus the candidate DAG does not have any constraints and + can be applied. -DCU _1_ is a candidate, and the candidate DAG reachable from DCU _1_ is only DCU -_1_ itself. DCU _1_ and thus the candidate DAG does not have any constraints and -can be applied. + ![](images/content-updates/simple-desynchronized-state-2.png) -![](images/content-updates/simple-desynchronized-state-3.png) +3. The content updates of the candidate DAG get applied to the surface atomically. -The content updates of the candidate DAG get applied to the surface atomically. + ![](images/content-updates/simple-desynchronized-state-3.png) -![](images/content-updates/simple-desynchronized-state-4.png) +4. T1 commits a DCU with a _buffer-sync_ constraint. It is a candidate but its DAG + can't be applied because it contains a constraint. -T1 commits a DCU with a _buffer-sync_ constraint. It is a candidate but its DAG -can't be applied because it contains a constraint. + ![](images/content-updates/simple-desynchronized-state-4.png) -![](images/content-updates/simple-desynchronized-state-5.png) +5. T1 commits another CU (DCU _3_) which is added at the end of the queue, with a + dependency to the previous CU (DCU _2_). Both DCU _2_ and DCU _3_ are + candidates, but both DAGs contain DCU _2_ with a constraint, and can't be + applied. -T1 commits another CU (DCU _3_) which is added at the end of the queue, with a -dependency to the previous CU (DCU _2_). Both DCU _2_ and DCU _3_ are -candidates, but both DAGs contain DCU _2_ with a constraint, and can't be -applied. + ![](images/content-updates/simple-desynchronized-state-5.png) -![](images/content-updates/simple-desynchronized-state-6.png) +6. When the constraint gets cleared, both DAGs can be applied to the surface + atomitcally (either only _2_, or _2_ and _3_). -When the constraint gets cleared, both DAGs can be applied to the surface -atomitcally (either only _2_, or _2_ and _3_). + ![](images/content-updates/simple-desynchronized-state-6.png) -**Simple Synchronized Case** +### Simple Synchronized Case -![](images/content-updates/simple-synchronized-state-1.png) +1. SS1 and SS2 are effectively synchronized. SS2 commits SCU _1_. -SS1 and SS2 are effectively synchronized. SS2 commits SCU _1_. + ![](images/content-updates/simple-synchronized-state-1.png) -![](images/content-updates/simple-synchronized-state-2.png) +2. SS1 commits SCU _2_. The direct child surfaces SS2 has the last SCU _1_ in its + queue, which is not reachable. This creates a dependency from SCU _2_ to SCU + _1_. -SS1 commits SCU _2_. The direct child surfaces SS2 has the last SCU _1_ in its -queue, which is not reachable. This creates a dependency from SCU _2_ to SCU -_1_. + ![](images/content-updates/simple-synchronized-state-2.png) -![](images/content-updates/simple-synchronized-state-3.png) +3. SS1 commits SCU _3_. The direct child surfaces SS2 has the last SCU _1_ in its + queue, which is already reachable by SCU _2_. No dependency to SCU _1_ is + created. A dependency to the previous CU of the same queue (SCU _2_) is created. -SS1 commits SCU _3_. The direct child surfaces SS2 has the last SCU _1_ in its -queue, which is already reachable by SCU _2_. No dependency to SCU _1_ is -created. A dependency to the previous CU of the same queue (SCU _2_) is created. + ![](images/content-updates/simple-synchronized-state-3.png) -![](images/content-updates/simple-synchronized-state-4.png) +4. T1 commit DCU _4_. It is a candidate, its DAG does not contain any constraint + and it can be applied. -T1 commit DCU _4_. It is a candidate, its DAG does not contain any constraint -and it can be applied. + ![](images/content-updates/simple-synchronized-state-4.png) -![](images/content-updates/simple-synchronized-state-5.png) +5. The DAG gets applied to the surfaces atomically. -The DAG gets applied to the surfaces atomically. + ![](images/content-updates/simple-synchronized-state-5.png) -**Complex Synchronized Subsurface Case 1** +### Complex Synchronized Subsurface Case 1 -![](images/content-updates/sync-subsurf-case1-1.png) +1. Every DCU (_1_ and _6_) contain CUs with constraints in their candidate DAG -Every DCU (_1_ and _6_) contain CUs with constraints in their candidate DAG + ![](images/content-updates/sync-subsurf-case1-1.png) -![](images/content-updates/sync-subsurf-case1-2.png) +2. Waiting until the _buffer-sync_ constrain on CU _1_ is cleared, the candidate + DAG of CU _1_ does not contain constraints and can be applied -Waiting until the _buffer-sync_ constrain on CU _1_ is cleared, the candidate -DAG of CU _1_ does not contain constraints and can be applied + ![](images/content-updates/sync-subsurf-case1-2.png) -![](images/content-updates/sync-subsurf-case1-3.png) +3. That leaves the candidate DAG of CU _6_ which still contains another CU with a + _buffer-sync_ constrain -That leaves the candidate DAG of CU _6_ which still contains another CU with a -_buffer-sync_ constrain + ![](images/content-updates/sync-subsurf-case1-3.png) -![](images/content-updates/sync-subsurf-case1-4.png) +4. Waiting until the _buffer-sync_ constrain on CU _6_ is cleared, the candidate + DAG of _6_ does not contain CUs with constraints and can be applied. -Waiting until the _buffer-sync_ constrain on CU _6_ is cleared, the candidate -DAG of _6_ does not contain CUs with constraints and can be applied. + ![](images/content-updates/sync-subsurf-case1-4.png) -![](images/content-updates/sync-subsurf-case1-5.png) +5. There is no DCU left and no constraint remaining. Nothing more can be applied + without a new CU. -There is no DCU left and no constraint remaining. Nothing more can be applied -without a new CU. + ![](images/content-updates/sync-subsurf-case1-5.png) -**Complex Synchronized Subsurface Case 2** +### Complex Synchronized Subsurface Case 2 -![](images/content-updates/sync-subsurf-case2-1.png) +1. Both DCUs (_1_ and _6_) have a reachable DAG containing CU _1_ with a constraint -Both DCUs (_1_ and _6_) have a reachable DAG containing CU _1_ with a constraint + ![](images/content-updates/sync-subsurf-case2-1.png) -![](images/content-updates/sync-subsurf-case2-2.png) +2. Waiting until the _buffer-sync_ constrain on _1_ is cleared, both DAGs contain + no CU with constraints and can be applied in any order -Waiting until the _buffer-sync_ constrain on _1_ is cleared, both DAGs contain -no CU with constraints and can be applied in any order + ![](images/content-updates/sync-subsurf-case2-2.png) -![](images/content-updates/sync-subsurf-case2-3.png) +3. That leaves the same state as in the previous case -That leaves the same state as in the previous case + ![](images/content-updates/sync-subsurf-case2-3.png) -**Synchronized to Desynchronized Subsurface** +### Synchronized to Desynchronized Subsurface -![](images/content-updates/sync-to-desync-subsurf-1.png) +1. There is one DCU (_4_) with its reachable DAG that cannot be applied because CU + _4_ contains a constraint -There is one DCU (_4_) with its reachable DAG that cannot be applied because CU -_4_ contains a constraint + ![](images/content-updates/sync-to-desync-subsurf-1.png) -![](images/content-updates/sync-to-desync-subsurf-2.png) +2. Surface _SS1_ transitions from effectively synchronized to effectively + desynchronized. SCU _2_ is reachable by DCU _4_ so nothing changes. -Surface _SS1_ transitions from effectively synchronized to effectively -desynchronized. SCU _2_ is reachable by DCU _4_ so nothing changes. + ![](images/content-updates/sync-to-desync-subsurf-2.png) -![](images/content-updates/sync-to-desync-subsurf-3.png) +3. Surface _SS1_ provides a new DCU (_5_) but because the CU before (_2_) is a + Synchronized CU, it is not a candidate -Surface _SS1_ provides a new DCU (_5_) but because the CU before (_2_) is a -Synchronized CU, it is not a candidate + ![](images/content-updates/sync-to-desync-subsurf-3.png) -**Synchronized to Desynchronized Transition** +### Synchronized to Desynchronized Transition -![](images/content-updates/sync-to-desync-transition-1.png) +1. There are four SCUs and all surfaces are effectively synchronized. -There are four SCUs and all surfaces are effectively synchronized. + ![](images/content-updates/sync-to-desync-transition-1.png) -![](images/content-updates/sync-to-desync-transition-2.png) +2. Surface _SS1_ transitions to effectively desynchronized and SCU _2_ becomes a + DCU because it is not reachable from a DCU -Surface _SS1_ transitions to effectively desynchronized and SCU _2_ becomes a -DCU because it is not reachable from a DCU + ![](images/content-updates/sync-to-desync-transition-2.png) -![](images/content-updates/sync-to-desync-transition-3.png) +3. Surface _SS2_ transitions to effectively desynchronized. SCUs _3_ and _4_ become + DCUs because they are not reachable from a DCU. SCU _1_ does not change because + it is reachable by DCU _2_. -Surface _SS2_ transitions to effectively desynchronized. SCUs _3_ and _4_ become -DCUs because they are not reachable from a DCU. SCU _1_ does not change because -it is reachable by DCU _2_. + ![](images/content-updates/sync-to-desync-transition-3.png) From 5231c0ee206d85dc985b9cc8895e3bec4b5b5db0 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 12 Feb 2026 15:45:53 +0100 Subject: [PATCH 1130/1152] doc: restore missing image files in docbook Signed-off-by: Julian Orth --- doc/publican/html/images/icon.svg | 19 +++++++++++++++++++ doc/publican/html/images/meson.build | 11 +++++++++++ doc/publican/meson.build | 1 + 3 files changed, 31 insertions(+) create mode 100644 doc/publican/html/images/icon.svg create mode 100644 doc/publican/html/images/meson.build diff --git a/doc/publican/html/images/icon.svg b/doc/publican/html/images/icon.svg new file mode 100644 index 00000000..b2f16d0f --- /dev/null +++ b/doc/publican/html/images/icon.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/doc/publican/html/images/meson.build b/doc/publican/html/images/meson.build new file mode 100644 index 00000000..cb80da66 --- /dev/null +++ b/doc/publican/html/images/meson.build @@ -0,0 +1,11 @@ +foreach src : files([ + 'icon.svg', + 'wayland.png', +]) + name = fs.name(src) + publican_inputs += fs.copyfile( + name, + install: true, + install_dir: publican_install_prefix + '/html/images', + ) +endforeach diff --git a/doc/publican/meson.build b/doc/publican/meson.build index 1b3965d5..c0a42155 100644 --- a/doc/publican/meson.build +++ b/doc/publican/meson.build @@ -66,6 +66,7 @@ publican_inputs += custom_target( ) subdir('html/css') +subdir('html/images') skip_validation = '--skip-validation' if get_option('docbook_validation') From 72805582eeb21a33f69ffd8088af5feb56529e13 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 24 Feb 2026 13:14:20 +0100 Subject: [PATCH 1131/1152] doc: fix cname-(suffix-)requirements These used to be macro-like xml things that expanded to the text this commit replaces them with. Signed-off-by: Isaac Freund --- doc/book/src/Message_XML.md | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/doc/book/src/Message_XML.md b/doc/book/src/Message_XML.md index 47b37796..c44deee9 100644 --- a/doc/book/src/Message_XML.md +++ b/doc/book/src/Message_XML.md @@ -33,7 +33,9 @@ of the XML file. **Required attributes** `name`="`cname`" - : The name of the protocol (a.k.a protocol extension). cname-requirements + : The name of the protocol (a.k.a protocol extension). The name must start + with one of the ASCII characters a-z, A-Z, or underscore, and the following + characters may additionally include numbers 0-9. The name should be globally unique. Protocols to be included in [wayland-protocols](https://gitlab.freedesktop.org/wayland/wayland-protocols) @@ -116,7 +118,9 @@ usage of the interface. **Required attributes** `name`="`cname`" - : The name of the interface. cname-requirements The name must be unique in the + : The name of the interface. The name must start with one of the ASCII + characters a-z, A-Z, or underscore, and the following characters may + additionally include numbers 0-9. The name must be unique in the protocol, and preferably it should also be globally unique to avoid API conflicts in language bindings of multiple protocols. @@ -174,7 +178,9 @@ The description element should be used to document the request. **Required attributes** `name`="`cname`" - : The name of the request. cname-requirements The name must be unique within + : The name of the request. The name must start with one of the ASCII + characters a-z, A-Z, or underscore, and the following characters may + additionally include numbers 0-9. The name must be unique within all requests and events in the containing interface. Code and language binding generators may use the name in the API they @@ -238,8 +244,10 @@ The description element should be used to document the event. **Required attributes** `name`="`cname`" - : The name of the event. cname-requirements The name must be unique within all - requests and events in the containing interface. + : The name of the event. The name must start with one of the ASCII characters + a-z, A-Z, or underscore, and the following characters may additionally + include numbers 0-9. The name must be unique within all requests and events + in the containing interface. Code and language binding generators may use the name in the API they create. The `name` of the containing interface provides the namespace for @@ -297,7 +305,9 @@ This element declares one argument for the request or the event. **Required attributes** `name`="`cname`" - : The name of the argument. cname-requirements The name must be unique within + : The name of the argument. The name must start with one of the ASCII + characters a-z, A-Z, or underscore, and the following characters may + additionally include numbers 0-9. The name must be unique within all the arguments of the parent element. `type`="`T`" @@ -435,7 +445,8 @@ integers. **Required attributes** `name`="`cname-suffix`" - : The name of the enumeration. cname-suffix-requirements The name must be + : The name of the enumeration. The name must contain only the ASCII characters + a-z, A-Z, 0-9, or underscore. The name cannot be empty. The name must be unique within all enumerations in the containing interface. The name is used as the namespace for all the contained entry elements. @@ -465,7 +476,8 @@ the containing enumeration. **Required attributes** `name`="`cname-suffix`" - : The name of a value in an enumeration. cname-suffix-requirements The name + : The name of a value in an enumeration. The name must contain only the ASCII + characters a-z, A-Z, 0-9, or underscore. The name cannot be empty. The name must be unique within all entry elements in the containing enum. `value`="`V`" From 7e47803e43282d7c26751d8f4cd98aa4868da67b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 12 May 2021 16:27:14 +0200 Subject: [PATCH 1132/1152] protocol: introduce wl_surface.get_release This new request allows clients to get per-surface-commit buffer release events. It supersedes wl_buffer.release. This functionality is also available via the linux-explicit-synchronization protocol, but requires the compositor to also support Linux synchronization fences. Adding this new request to the core protocol allows any compositor to implement the functionality. Signed-off-by: Simon Ser Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/203 References: https://gitlab.freedesktop.org/wayland/wayland/-/issues/46 --- protocol/wayland.xml | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 58e5649e..830f3e6b 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -190,7 +190,7 @@ - + A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple @@ -1415,7 +1415,7 @@ - + A surface is a rectangular area that may be displayed on zero or more outputs, and shown any number of times at the compositor's @@ -1471,6 +1471,7 @@ + @@ -1525,9 +1526,11 @@ If a pending wl_buffer has been committed to more than one wl_surface, the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this - case. Alternatively, a client could create multiple wl_buffer objects - from the same backing storage or use a protocol extension providing - per-commit release notifications. + case. Instead, clients hitting this case should use + wl_surface.get_release or use a protocol extension providing per-commit + release notifications (if none of these options are available, a + fallback can be implemented by creating multiple wl_buffer objects from + the same backing storage). Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release @@ -1931,6 +1934,32 @@ + + + + + + Create a callback for the release of the buffer attached by the client + with wl_surface.attach. + + The compositor will release the buffer when it has finished its usage of + the underlying storage for the relevant commit. Once the client receives + this event, and assuming the associated buffer is not pending release + from other wl_surface.commit requests, the client can safely re-use the + buffer. + + Release callbacks are double-buffered state, and will be associated + with the pending buffer at wl_surface.commit time. + + The callback_data passed in the wl_callback.done event is unused and + is always zero. + + Sending this request without attaching a non-null buffer in the same + content update is a protocol error. The compositor will send the + no_buffer error in this case. + + + From ef336e8b80f0cbfc26a7f7ed6b8ea0e5012f9822 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 23 Jan 2026 14:59:21 +0100 Subject: [PATCH 1133/1152] protocol: fix wl_region version wl_region is not a frozen interface and therefore should have the version of the parent object, wl_compositor. Signed-off-by: Julian Orth --- protocol/wayland.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 830f3e6b..05ef85e0 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -3078,7 +3078,7 @@ - + A region object describes an area. From bb2fda519af736fd0e76c987a3fed2ddc44163c3 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 27 Jan 2026 14:16:41 +0100 Subject: [PATCH 1134/1152] protocol: add wl_compositor destructor Signed-off-by: Julian Orth --- protocol/wayland.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 05ef85e0..9e69a9e4 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -210,6 +210,14 @@ + + + + + + This request destroys the wl_compositor. This has no effect on any other objects. + + @@ -3078,7 +3086,7 @@ - + A region object describes an area. From cba2754230177024869e1400c51de201d0a8ba69 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 23 Jan 2026 15:20:12 +0100 Subject: [PATCH 1135/1152] protocol: add wl_data_device_manager destructors Signed-off-by: Julian Orth --- protocol/wayland.xml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 9e69a9e4..6d3a056f 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -546,7 +546,7 @@ - + A wl_data_offer represents a piece of data offered for transfer by another client (the source client). It is used by the @@ -739,7 +739,7 @@ - + The wl_data_source object is the source side of a wl_data_offer. It is created by the source client in a data transfer and @@ -894,7 +894,7 @@ - + There is one wl_data_device per seat which can be obtained from the global wl_data_device_manager singleton. @@ -1055,7 +1055,7 @@ - + The wl_data_device_manager is a singleton global object that provides access to inter-client data transfer mechanisms such as @@ -1117,6 +1117,15 @@ + + + + + + This request destroys the wl_data_device_manager. This has no effect on any other + objects. + + From cd4e6a14517c71285acc976fe10b12e490d72a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Yhuel?= Date: Tue, 16 Sep 2025 13:15:34 +0200 Subject: [PATCH 1136/1152] client: fix crash when creating proxies with no queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, it worked if the client did set a queue on the proxy before any event was received. Now we have the "warning: queue xxx destroyed while proxies still attached", then a crash if one of the proxies is used to create a proxy. Fixes: 674145dc3f ("client: Track the proxies attached to a queue") Fixes: 0ba650202e ("client: Warn when a queue is destroyed with attached proxies") Signed-off-by: Loïc Yhuel --- src/wayland-client.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/wayland-client.c b/src/wayland-client.c index ed686b5c..50b3b4b2 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -499,7 +499,10 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, return NULL; } - wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + if (proxy->queue != NULL) + wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + else + wl_list_init(&proxy->queue_link); return proxy; } @@ -560,7 +563,10 @@ wl_proxy_create_for_id(struct wl_proxy *factory, return NULL; } - wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + if (proxy->queue != NULL) + wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); + else + wl_list_init(&proxy->queue_link); return proxy; } @@ -2801,7 +2807,10 @@ wl_proxy_create_wrapper(void *proxy) wrapper->flags = WL_PROXY_FLAG_WRAPPER; wrapper->refcount = 1; - wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link); + if (wrapper->queue != NULL) + wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link); + else + wl_list_init(&wrapper->queue_link); pthread_mutex_unlock(&wrapped_proxy->display->mutex); From dad4404d92b8fac83078b16c37b5bada1aaf940c Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Thu, 18 Sep 2025 17:28:08 +0300 Subject: [PATCH 1137/1152] tests: Add test for using a proxy with a destroyed queue as a factory Signed-off-by: Alexandros Frantzis --- tests/queue-test.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/queue-test.c b/tests/queue-test.c index 7dfdd306..2b2d9ad4 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -634,6 +634,49 @@ client_test_queue_dispatch_timeout(void) exit(0); } +/* Try to use a proxy with a destroyed queue as a factory for + * another proxy (either normal or wrapper). This should succeed + * although the new proxy may not be useful until a queue is attached. + * The following code is safe to perform in the context of the test, since + * we are not flushing the display write buffer, neither explicitly + * (wl_display_flush()) nor implicitly (we don't place enough data to + * fill the display buffer and cause an auto-flush). */ +static void +client_test_queue_destroy_then_use_proxy_as_factory(void) +{ + struct wl_display *display; + struct wl_event_queue *queue; + struct wl_registry *registry, *registry_wrapper; + struct wl_proxy *proxy; + + display = wl_display_connect(NULL); + assert(display); + + /* Create registry with a queue that's immediately destroyed. */ + queue = wl_display_create_queue(display); + assert(queue); + registry = wl_display_get_registry(display); + assert(registry); + wl_proxy_set_queue((struct wl_proxy *) registry, queue); + wl_event_queue_destroy(queue); + + /* Scenario 1: Create a proxy using the registry (never flushed, + * so details don't matter). */ + proxy = wl_registry_bind(registry, 1000, &wl_output_interface, 1); + assert(proxy); + + /* Scenario 2: Create a wrapper proxy using the registry. */ + registry_wrapper = wl_proxy_create_wrapper(registry); + assert(registry_wrapper); + + wl_proxy_wrapper_destroy((struct wl_proxy *) registry_wrapper); + wl_proxy_destroy(proxy); + wl_registry_destroy(registry); + wl_display_disconnect(display); + + exit(0); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -796,3 +839,15 @@ TEST(queue_dispatch_timeout) display_destroy(d); } + +TEST(queue_destroy_then_use_proxy_as_factory) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_destroy_then_use_proxy_as_factory); + display_run(d); + + display_destroy(d); +} From 290ce2a9c13019b1ee2841b0e1881da4e407e9fb Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Thu, 17 Apr 2025 18:30:11 -0400 Subject: [PATCH 1138/1152] protocol: elaborate on drm_fourcc.h and wl_shm.format codes Wayland clients should not assume the format list will not grow, or assume the format descriptions in the Wayland protocol are complete. (The latter fact is clear for descriptionless enum entries like XRGB8888_A8; but, for example, the full XRGB16161616F format description explicitly requires IEEE 754 binary16 floats instead of bfloat16 or ARM's alternative half precision variant.) Signed-off-by: Manuel Stoeckl --- protocol/wayland.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 6d3a056f..19f18479 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -312,7 +312,8 @@ The drm format codes match the macros defined in drm_fourcc.h, except argb8888 and xrgb8888. The formats actually supported by the compositor - will be reported by the format event. + will be reported by the format event. See drm_fourcc.h for more detailed + format descriptions. For all wl_shm formats and unless specified in another protocol extension, pre-multiplied alpha is used for pixel values. @@ -482,6 +483,10 @@ Informs the client about a valid pixel format that can be used for buffers. Known formats include argb8888 and xrgb8888. + + Extensions to drm_fourcc.h (or the format enum) do not require + increasing the wl_shm version; as a result, clients may receive format + codes which were not in the list at the time the client was made. From fe3a02c18a897c7cd89d50c1300305ffb7f55d86 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 30 Jan 2026 09:57:36 +0100 Subject: [PATCH 1139/1152] util: assert alloc is consistent with data in wl_array_add() struct wl_array may be constructed by users manually from a foreign data pointer: uint32_t states[] = {1, 2, 3}; struct wl_array arr = { .data = states, .size = sizeof(states) / sizeof(states[0]), }; This is useful to avoid the need to allocate when sending Wayland messages. Users need to be careful not to use wl_array_add() on such arrays: the function will misbehave by leaving garbage at the start of the new buffer when reallocating. Add an assert to guard against wl_array_add() calls in this situation, to have a clear crash instead of undefined behavior. Signed-off-by: Simon Ser --- src/wayland-util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wayland-util.c b/src/wayland-util.c index 7231346b..f5518676 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -121,6 +121,9 @@ wl_array_add(struct wl_array *array, size_t size) alloc *= 2; if (array->alloc < alloc) { + if (array->alloc == 0 && array->data != NULL) + wl_abort("data is non-NULL with zero alloc"); + if (array->alloc > 0) data = realloc(array->data, alloc); else From df10ef181e90ba8d0ce86e5f5e7280dad5d894c7 Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Tue, 3 Mar 2026 03:55:20 -0300 Subject: [PATCH 1140/1152] Fix typos Signed-off-by: Diego Viola --- doc/book/src/Compositors.md | 2 +- doc/publican/Client.xml | 2 +- tests/data/bad-identifier-protocol.xml | 2 +- tests/test-compositor.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/book/src/Compositors.md b/doc/book/src/Compositors.md index 251be316..61d1bdbd 100644 --- a/doc/book/src/Compositors.md +++ b/doc/book/src/Compositors.md @@ -66,7 +66,7 @@ Another option is to use a nested Wayland instance. For this, the Wayland server will have to be a library that the host application links to. The host application will then pass the Wayland server socket name to the embedded application, and will need to implement the Wayland compositor interface. The -host application composites the client surfaces as part of it's window, that is, +host application composites the client surfaces as part of its window, that is, in the web page or in the panel. The benefit of nesting the Wayland server is that it provides the requests the embedded client needs to inform the host about buffer updates and a mechanism for forwarding input events from the host diff --git a/doc/publican/Client.xml b/doc/publican/Client.xml index 19bf3e95..cb21598f 100644 --- a/doc/publican/Client.xml +++ b/doc/publican/Client.xml @@ -25,7 +25,7 @@ are received from the server until they can be processed. Multi-threading is supported by creating an additional wl_event_queue for each additional thread, each object can have - it's events placed in a particular queue, so potentially a + its events placed in a particular queue, so potentially a different thread could be made to handle the events for each object created. diff --git a/tests/data/bad-identifier-protocol.xml b/tests/data/bad-identifier-protocol.xml index 7a172045..1aafb32d 100644 --- a/tests/data/bad-identifier-protocol.xml +++ b/tests/data/bad-identifier-protocol.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test-compositor.c b/tests/test-compositor.c index efec31fa..f412fe6e 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -517,7 +517,7 @@ struct client *client_connect(void) assert(c->wl_display && "Failed connecting to display"); /* create test_compositor proxy. Do it with temporary - * registry so that client can define it's own listener later */ + * registry so that client can define its own listener later */ reg = wl_display_get_registry(c->wl_display); assert(reg); wl_registry_add_listener(reg, ®istry_listener, c); From fe4d7620ddd33797f554909f9c9ca99f0a192e10 Mon Sep 17 00:00:00 2001 From: Rudi Heitbaum Date: Wed, 4 Mar 2026 08:28:56 +1100 Subject: [PATCH 1141/1152] cursor: fix discards 'const' qualifier Fixes: ../cursor/xcursor.c: In function 'xcursor_next_path': ../cursor/xcursor.c:610:23: warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] 610 | char *colon = strchr(path, ':'); | ^~~~~~ Signed-off-by: Rudi Heitbaum --- cursor/xcursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursor/xcursor.c b/cursor/xcursor.c index 6e54cdbd..28aab045 100644 --- a/cursor/xcursor.c +++ b/cursor/xcursor.c @@ -607,7 +607,7 @@ xcursor_build_fullname(const char *dir, const char *subdir, const char *file) static const char * xcursor_next_path(const char *path) { - char *colon = strchr(path, ':'); + const char *colon = strchr(path, ':'); if (!colon) return NULL; From 4d13366fcc3213f197074a3f716aec41f32f81ef Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 3 Mar 2026 20:32:24 +0300 Subject: [PATCH 1142/1152] server: improve version mismatch error message "1 < 2" is obviously true but not very useful information by itself. Provide a bit more context. Signed-off-by: Kirill Primak --- src/wayland-server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index c81d98f1..217613ff 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -450,11 +450,11 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) resource->version > 0 && resource->version < since) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, - "invalid method %d (since %d < %d)" - ", object %s#%u", - opcode, resource->version, since, + "invalid version for %s#%u.%s (%d, need at least %d)", object->interface->name, - object->id); + object->id, + message->name, + resource->version, since); break; } From a58bcd7481db4b20533b2b3667df6c45e7ad7225 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 24 Feb 2026 12:43:43 +0100 Subject: [PATCH 1143/1152] doc: add frozen=true interface attribute This is useful for scanners that use knowledge of the object creation hierarchy such as zig-wayland [1]. Currently zig-wayland uses a hardcoded list of frozen interfaces. [1]: https://codeberg.org/ifreund/zig-wayland Signed-off-by: Isaac Freund --- doc/book/src/Message_XML.md | 12 +++++++++++- protocol/wayland.dtd | 1 + protocol/wayland.xml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/book/src/Message_XML.md b/doc/book/src/Message_XML.md index c44deee9..2a3c5f3f 100644 --- a/doc/book/src/Message_XML.md +++ b/doc/book/src/Message_XML.md @@ -140,7 +140,8 @@ usage of the interface. the interfaces part of the same interface ancestry tree. The exception to this rule are interfaces which are forever stuck to version 1, which is usually caused by having multiple parent interfaces with independent - ancestor global interfaces. + ancestor global interfaces. In this case, the `frozen="true"` attribute + described below should be used. A protocol object may have any defined version of the interface. The version of the object is determined at runtime either by inheritance from another @@ -152,6 +153,15 @@ usage of the interface. thoroughly updated as required. In such cases the object shall function as with the highest defined interface version. +**Optional attributes** + +`frozen`="`true`" + : The interface is frozen and forever stuck at version 1. + + This attribute should be applied to interfaces that have multiple parent + interfaces with independent ancestor global interfaces, for example + `wl_buffer` and `wl_callback`. + ### request Parent elements: interface diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd index b97372c5..ae8340d6 100644 --- a/protocol/wayland.dtd +++ b/protocol/wayland.dtd @@ -4,6 +4,7 @@ + diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 19f18479..513b8fd8 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -173,7 +173,7 @@ - + Clients can handle the 'done' event to get notified when the related request is done. @@ -503,7 +503,7 @@ - + A buffer provides the content for a wl_surface. Buffers are created through factory interfaces such as wl_shm, wp_linux_buffer_params From c0a6e73606edb2477dc491496b0235ce1212de59 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 24 Feb 2026 12:51:02 +0100 Subject: [PATCH 1144/1152] scanner: enforce frozen attribute Signed-off-by: Isaac Freund --- src/scanner.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/scanner.c b/src/scanner.c index 1b71e60c..cd5f7fea 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -736,6 +736,7 @@ start_element(void *data, const char *element_name, const char **atts) const char *allow_null = NULL; const char *enumeration_name = NULL; const char *bitfield = NULL; + const char *frozen = NULL; int i, version = 0; ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); @@ -765,6 +766,8 @@ start_element(void *data, const char *element_name, const char **atts) enumeration_name = atts[i + 1]; if (strcmp(atts[i], "bitfield") == 0) bitfield = atts[i + 1]; + if (strcmp(atts[i], "frozen") == 0) + frozen = atts[i + 1]; } ctx->character_data_length = 0; @@ -784,6 +787,20 @@ start_element(void *data, const char *element_name, const char **atts) if (version == 0) fail(&ctx->loc, "no interface version given"); + if (frozen) { + if (strcmp(frozen, "true") == 0) { + if (version != 1) { + fail(&ctx->loc, + "frozen interface must have version 1"); + } + } else if (strcmp(frozen, "false") != 0) { + fail(&ctx->loc, + "invalid value (%s) frozen attribute " + "(only true/false are accepted)", + frozen); + } + } + validate_identifier(&ctx->loc, name, STANDALONE_IDENT); interface = create_interface(ctx->loc, name, version); ctx->interface = interface; From 69aabecd1871a2544b12a9498ec614e705eecedd Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 3 Mar 2026 21:01:00 +0300 Subject: [PATCH 1145/1152] server: don't disclose the existence of invisible globals Otherwise, a client iterate over a range of names binding with deliberately incorrect interfaces and receive error messages with expected interfaces regardless of global visibility. Signed-off-by: Kirill Primak --- src/wayland-server.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 217613ff..3d2a06b6 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1054,10 +1054,10 @@ registry_bind(struct wl_client *client, if (global->name == name) break; - if (&global->link == &display->global_list) + if (&global->link == &display->global_list || !wl_global_is_visible(client, global)) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid global %s (%d)", interface, name); + "global %s (%"PRIu32") is unavailable", interface, name); else if (strcmp(global->interface->name, interface) != 0) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, @@ -1074,10 +1074,6 @@ registry_bind(struct wl_client *client, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid version for global %s (%d): have %d, wanted %d", interface, name, global->version, version); - else if (!wl_global_is_visible(client, global)) - wl_resource_post_error(resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid global %s (%d)", interface, name); else global->bind(client, global->data, version, id); } From 13d906a629650198a2b8ca47b83e2707093033e3 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 3 Mar 2026 21:07:42 +0300 Subject: [PATCH 1146/1152] server: improve wl_registry.bind error messages - Consistently use PRIu32 for global names (uint32_t) - Use expected/got instead of have/wanted (which were used differently anyway) Signed-off-by: Kirill Primak --- src/wayland-server.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 3d2a06b6..31cc9824 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1061,18 +1061,17 @@ registry_bind(struct wl_client *client, else if (strcmp(global->interface->name, interface) != 0) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid interface for global %u: " - "have %s, wanted %s", - name, interface, global->interface->name); + "invalid interface for global %"PRIu32": expected %s, got %s", + name, global->interface->name, interface); else if (version == 0) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid version for global %s (%d): 0 is not a valid version", + "invalid version for global %s (%"PRIu32"): 0 is not a valid version", interface, name); else if (global->version < version) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid version for global %s (%d): have %d, wanted %d", + "invalid version for global %s (%"PRIu32"): expected at most %d, got %d", interface, name, global->version, version); else global->bind(client, global->data, version, id); From e6aeed9816f9fa202ed49318b7b25f867676999a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 Mar 2026 19:10:51 +0100 Subject: [PATCH 1147/1152] build: bump version to 1.24.91 for the RC1 release Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 7ad5ac06..d866b8a8 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.24.90', + version: '1.24.91', license: 'MIT', meson_version: '>= 0.64.0', default_options: [ From bec2bcddd84056eaa6f9abfa778a9e16929c1ece Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 Mar 2026 12:31:35 +0100 Subject: [PATCH 1148/1152] ci: upgrade FreeBSD to v14.4 Signed-off-by: Simon Ser --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 17298274..cd7b5113 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -305,11 +305,11 @@ armv7-release-debian-build: .os-freebsd: variables: BUILD_OS: freebsd - FDO_DISTRIBUTION_VERSION: "14.3" + FDO_DISTRIBUTION_VERSION: "14.4" FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2025-07-20.0" + FDO_DISTRIBUTION_TAG: "2026-03-10.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false" From 53509f09bace705d0a2adbe7d28230469c58f1cb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 20 Mar 2026 11:17:40 +0100 Subject: [PATCH 1149/1152] build: re-open main branch for regular development Signed-off-by: Simon Ser --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d866b8a8..cb6c2385 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'wayland', 'c', - version: '1.24.91', + version: '1.25.90', license: 'MIT', meson_version: '>= 0.64.0', default_options: [ From c048101ca92c91b22d8504bc2beee683a629f758 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 13 Mar 2026 17:35:27 +0200 Subject: [PATCH 1150/1152] Add wl_fixes.ack_global_remove() The wl_global_remove() function was introduce to help mitigate clients getting unintentionally disconnected if a global is added and removed in a short burst. The intended usage was: - the compositor calls wl_global_remove() - after a certain period of time, the compositor calls wl_global_destroy() Unfortunately, it did not fully fix the issue due to the way monotonic clock works on Linux. Specifically, it can tick even during sleep. This change adds a slightly better way to handle global removal. With the proposed changes, the clients need to signal to the compositor that they won't bind the global anymore. After all clients have acknowledged a wl_registry.global_remove, the compositor can finally destroy the global. Signed-off-by: Vlad Zahorodnii --- protocol/wayland.xml | 40 +++++- src/wayland-server-core.h | 12 ++ src/wayland-server.c | 273 ++++++++++++++++++++++++++++++++------ tests/display-test.c | 223 +++++++++++++++++++++++++++++++ tests/test-compositor.c | 22 ++- tests/test-compositor.h | 1 + 6 files changed, 521 insertions(+), 50 deletions(-) diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 513b8fd8..11f0de36 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -3335,12 +3335,20 @@ - + This global fixes problems with other core-protocol interfaces that cannot be fixed in these interfaces themselves. + + + These errors can be emitted in response to wl_fixes requests. + + + + @@ -3360,6 +3368,36 @@ + + + + Acknowledge the removal of the specified global. + + If no global with the specified name exists or the global is not removed, + the wl_fixes.invalid_ack_remove protocol error will be posted. + + Due to the Wayland protocol being asynchronous, the wl_global objects + cannot be destroyed immediately. For example, if a wl_global is removed + and a client attempts to bind that global around same time, it can + result in a protocol error due to an unknown global name in the bind + request. + + In order to avoid crashing clients, the compositor should remove the + wl_global once it is guaranteed that no more bind requests will come. + + The wl_fixes.ack_global_remove() request is used to signal to the + compositor that the client will not bind the given global anymore. After + all clients acknowledge the removal of the global, the compositor can + safely destroy it. + + The client must call the wl_fixes.ack_global_remove() request in + response to a wl_registry.global_remove() event even if it did not bind + the corresponding global. + + + + diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index c8a64772..cc08de58 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -222,10 +222,13 @@ wl_display_set_default_max_buffer_size(struct wl_display *display, size_t max_buffer_size); struct wl_client; +struct wl_global; typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, uint32_t version, uint32_t id); +typedef void (*wl_global_withdrawn_func_t)(struct wl_global *global); + uint32_t wl_display_get_serial(const struct wl_display *display); @@ -253,6 +256,10 @@ wl_global_create(struct wl_display *display, void wl_global_remove(struct wl_global *global); +void +wl_global_set_withdrawn_listener(struct wl_global *global, + wl_global_withdrawn_func_t func); + void wl_global_destroy(struct wl_global *global); @@ -725,6 +732,11 @@ wl_display_add_protocol_logger(struct wl_display *display, void wl_protocol_logger_destroy(struct wl_protocol_logger *logger); +void +wl_fixes_handle_ack_global_remove(struct wl_resource *fixes_resource, + struct wl_resource *registry_resource, + uint32_t global_name); + #ifdef __cplusplus } #endif diff --git a/src/wayland-server.c b/src/wayland-server.c index 31cc9824..932ac662 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -115,17 +115,31 @@ struct wl_display { size_t max_buffer_size; }; +struct wl_registry { + struct wl_display *display; + struct wl_list offer_list; +}; + struct wl_global { struct wl_display *display; const struct wl_interface *interface; + struct wl_list offer_list; uint32_t name; uint32_t version; void *data; wl_global_bind_func_t bind; + wl_global_withdrawn_func_t withdrawn; struct wl_list link; bool removed; }; +struct wl_global_offer { + struct wl_list global_link; /**< in struct wl_global::offer_list */ + struct wl_list registry_link; /**< in struct wl_registry::offer_list */ + struct wl_resource *registry_resource; + struct wl_global *global; +}; + struct wl_resource { struct wl_object object; wl_resource_destroy_func_t destroy; @@ -1048,7 +1062,8 @@ registry_bind(struct wl_client *client, const char *interface, uint32_t version, uint32_t id) { struct wl_global *global; - struct wl_display *display = resource->data; + struct wl_registry *registry = resource->data; + struct wl_display *display = registry->display; wl_list_for_each(global, &display->global_list, link) if (global->name == name) @@ -1100,9 +1115,76 @@ display_sync(struct wl_client *client, } static void -unbind_resource(struct wl_resource *resource) +wl_global_announce(struct wl_global *global, + struct wl_resource *registry_resource) { + struct wl_global_offer *offer; + struct wl_registry *registry = registry_resource->data; + + offer = zalloc(sizeof *offer); + if (offer == NULL) { + wl_resource_post_no_memory(registry_resource); + return; + } + + offer->registry_resource = registry_resource; + offer->global = global; + wl_list_insert(&global->offer_list, &offer->global_link); + wl_list_insert(®istry->offer_list, &offer->registry_link); + + wl_resource_post_event(registry_resource, + WL_REGISTRY_GLOBAL, + global->name, + global->interface->name, + global->version); +} + +static void +wl_global_offer_destroy(struct wl_global_offer *offer) +{ + wl_list_remove(&offer->global_link); + wl_list_remove(&offer->registry_link); + free(offer); +} + +static void +wl_global_offer_done(struct wl_global_offer *offer) +{ + struct wl_global *global = offer->global; + + wl_global_offer_destroy(offer); + + if (global->removed && global->withdrawn && wl_list_empty(&global->offer_list)) + global->withdrawn(global); +} + +static struct wl_global_offer * +wl_registry_find_offer(struct wl_registry *registry, + uint32_t global_name) +{ + struct wl_global_offer *offer; + + wl_list_for_each(offer, ®istry->offer_list, registry_link) { + if (offer->global->name == global_name) + return offer; + } + + return NULL; +} + +static void +unbind_registry_resource(struct wl_resource *resource) +{ + struct wl_registry *registry = resource->data; + struct wl_global_offer *offer; + + while (!wl_list_empty(®istry->offer_list)) { + offer = wl_container_of(registry->offer_list.next, offer, registry_link); + wl_global_offer_done(offer); + } + wl_list_remove(&resource->link); + free(registry); } static void @@ -1112,6 +1194,7 @@ display_get_registry(struct wl_client *client, struct wl_display *display = resource->data; struct wl_resource *registry_resource; struct wl_global *global; + struct wl_registry *registry; registry_resource = wl_resource_create(client, &wl_registry_interface, 1, id); @@ -1120,20 +1203,25 @@ display_get_registry(struct wl_client *client, return; } + registry = zalloc(sizeof *registry); + if (registry == NULL) { + wl_client_post_no_memory(client); + return; + } + + registry->display = display; + wl_list_init(®istry->offer_list); + wl_resource_set_implementation(registry_resource, ®istry_interface, - display, unbind_resource); + registry, unbind_registry_resource); wl_list_insert(&display->registry_resource_list, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) if (wl_global_is_visible(client, global) && !global->removed) - wl_resource_post_event(registry_resource, - WL_REGISTRY_GLOBAL, - global->name, - global->interface->name, - global->version); + wl_global_announce(global, registry_resource); } static const struct wl_display_interface display_interface = { @@ -1399,52 +1487,24 @@ wl_global_create(struct wl_display *display, global->version = version; global->data = data; global->bind = bind; + global->withdrawn = NULL; global->removed = false; wl_list_insert(display->global_list.prev, &global->link); + wl_list_init(&global->offer_list); wl_list_for_each(resource, &display->registry_resource_list, link) if (wl_global_is_visible(resource->client, global)) - wl_resource_post_event(resource, - WL_REGISTRY_GLOBAL, - global->name, - global->interface->name, - global->version); + wl_global_announce(global, resource); return global; } -/** Remove the global - * - * \param global The Wayland global. - * - * Broadcast a global remove event to all clients without destroying the - * global. This function can only be called once per global. - * - * wl_global_destroy() removes the global and immediately destroys it. On - * the other end, this function only removes the global, allowing clients - * that have not yet received the global remove event to continue to bind to - * it. - * - * This can be used by compositors to mitigate clients being disconnected - * because a global has been added and removed too quickly. Compositors can call - * wl_global_remove(), then wait an implementation-defined amount of time, then - * call wl_global_destroy(). Note that the destruction of a global is still - * racy, since clients have no way to acknowledge that they received the remove - * event. - * - * \since 1.17.90 - */ -WL_EXPORT void -wl_global_remove(struct wl_global *global) +static void +wl_global_send_removed(struct wl_global *global) { struct wl_display *display = global->display; struct wl_resource *resource; - if (global->removed) - wl_abort("wl_global_remove: called twice on the same " - "global '%s#%"PRIu32"'", global->interface->name, - global->name); - wl_list_for_each(resource, &display->registry_resource_list, link) if (wl_global_is_visible(resource->client, global)) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, @@ -1453,12 +1513,100 @@ wl_global_remove(struct wl_global *global) global->removed = true; } +/** Remove the global + * + * \param global The Wayland global. + * + * Broadcast a global remove event to all clients without destroying the + * global. This function can only be called once per global. + * + * This can be used by compositors to mitigate clients being disconnected + * because a global has been added and removed too quickly. + * + * Due to the Wayland protocol being asynchronous, the wl_global objects + * cannot be destroyed immediately. For example, if a wl_global is destroyed + * and a client attempts to bind that global around same time, it can + * result in a protocol error due to an unknown global name in the bind request. + * + * In order to avoid crashing clients, the compositor should destroy the + * wl_global once it is guaranteed that no more bind requests will come. + * + * The recommended way to destroy globals is as follows: + * + * - the compositor registers a callback using the wl_global_set_withdrawn_listener() + * function, which will be called when it is safe to call wl_global_destroy(); + * - the compositor calls wl_global_remove(). This will broadcast + * wl_registry.global_remove events to all clients; + * - upon receiving a wl_registry.global_remove event, a client must + * reply to it by calling the wl_fixes.ack_global_remove() request. The + * client must call the wl_fixes.ack_global_remove() request even if it + * did not bind the global; + * - the compositor will call the wl_fixes_handle_ack_global_remove() function when + * it receives the wl_fixes.ack_global_remove() request from the client; + * - after all clients have acknowledged the global removal, the "withdrawn" + * callback will be called to notify the compositor that the + * wl_global_destroy() function can be called now. + * + * \sa wl_global_set_withdrawn_listener + * \sa wl_fixes_handle_ack_global_remove + * \since 1.17.90 + */ +WL_EXPORT void +wl_global_remove(struct wl_global *global) +{ + if (global->removed) + wl_abort("wl_global_remove: called twice on the same " + "global '%s#%"PRIu32"'", global->interface->name, + global->name); + + wl_global_send_removed(global); + + if (global->withdrawn && wl_list_empty(&global->offer_list)) + global->withdrawn(global); +} + +/** Set the withdrawn callback. + * + * \param global The Wayland global. + * \param func The withdrawn callback. + * + * The withdrawn callback notifies the compositor that the global can be + * safely destroyed by calling wl_global_destroy(). The callback will be called + * in the following cases: + * + * - immediately by wl_global_remove(), if there are no registeries where the + * global was announced; + * - or some time later after wl_global_remove(), due to either receiving the + * last wl_fixes_handle_ack_global_remove() or getting the last wl_registry + * where the global was announced destroyed. + * + * The withdrawn callback will never be called without prior wl_global_remove(). + * + * \sa wl_fixes_handle_ack_global_remove + * \since 1.26 + */ +WL_EXPORT void +wl_global_set_withdrawn_listener(struct wl_global *global, + wl_global_withdrawn_func_t func) +{ + global->withdrawn = func; +} + WL_EXPORT void wl_global_destroy(struct wl_global *global) { + struct wl_global_offer *offer; + if (!global->removed) - wl_global_remove(global); + wl_global_send_removed(global); + wl_list_remove(&global->link); + + while (!wl_list_empty(&global->offer_list)) { + offer = wl_container_of(global->offer_list.next, offer, global_link); + wl_global_offer_destroy(offer); + } + free(global); } @@ -2709,6 +2857,47 @@ wl_display_remove_global(struct wl_display *display, struct wl_global *global) wl_global_destroy(global); } +/** Acknowledge global removal by a client + * + * \param fixes_resource The wl_fixes resource. + * \param registry_resource The wl_registry resource. + * \param global_name The unique id of the global. + * + * The compositor should call this function from the wl_fixes.ack_global_remove + * request implementation. + * + * libwayland-server automatically takes care of the implied ack-remove due + * to client disconnection or explicit wl_resource_destroy() of the wl_registry + * resource. + * + * \sa wl_global_remove + * \sa wl_global_set_withdrawn_listener + * \since 1.26 + */ +WL_EXPORT void +wl_fixes_handle_ack_global_remove(struct wl_resource *fixes_resource, + struct wl_resource *registry_resource, + uint32_t global_name) +{ + struct wl_global_offer *offer; + struct wl_registry *registry = registry_resource->data; + + offer = wl_registry_find_offer(registry, global_name); + if (!offer) { + wl_resource_post_error(fixes_resource, WL_FIXES_ERROR_INVALID_ACK_REMOVE, + "the given registry did not announce global %u", global_name); + return; + } + + if (!offer->global->removed) { + wl_resource_post_error(fixes_resource, WL_FIXES_ERROR_INVALID_ACK_REMOVE, + "global %u is not removed", global_name); + return; + } + + wl_global_offer_done(offer); +} + /** \endcond */ /* Functions at the end of this file are deprecated. Instead of adding new diff --git a/tests/display-test.c b/tests/display-test.c index fe78b521..e6efa41e 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -51,6 +51,63 @@ #include "tests-server-protocol.h" #include "tests-client-protocol.h" +static void +registry_handle_global_noop(void *data, + struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t ver) +{ +} + +static void +registry_handle_global_remove_noop(void *data, + struct wl_registry *registry, + uint32_t id) +{ +} + +static void +fixes_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +fixes_destroy_registry(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *registry) +{ + wl_resource_destroy(registry); +} + +static void +fixes_ack_global_remove(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *registry, + uint32_t global_id) +{ + wl_fixes_handle_ack_global_remove(resource, registry, global_id); +} + +static const struct wl_fixes_interface fixes_implementation = { + .destroy = fixes_destroy, + .destroy_registry = fixes_destroy_registry, + .ack_global_remove = fixes_ack_global_remove, +}; + +static void +bind_fixes(struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_fixes_interface, version, id); + wl_resource_set_implementation(resource, &fixes_implementation, NULL, NULL); +} + struct display_destroy_listener { struct wl_listener listener; int done; @@ -1695,6 +1752,172 @@ TEST(global_remove) display_destroy(d); } +static void +registry_ack_global_remove_handle_global_remove(void *data, + struct wl_registry *registry, + uint32_t id) +{ + struct client *client = data; + + wl_fixes_ack_global_remove(client->wl_fixes, registry, id); +} + +static struct wl_registry_listener registry_ack_global_remove_listener = { + .global = registry_handle_global_noop, + .global_remove = registry_ack_global_remove_handle_global_remove, +}; + +static void +ack_global_remove_client(void *data) +{ + struct client *c = client_connect(); + struct wl_registry *registry; + struct wl_registry_listener *registry_listener = data; + int ret; + + registry = wl_display_get_registry(c->wl_display); + wl_registry_add_listener(registry, + registry_listener, + c); + + ret = wl_display_roundtrip(c->wl_display); + assert(ret >= 0); + + /* yield the control back to the compositor so it can remove + * the global */ + assert(stop_display(c, 1) >= 0); + + /* check if there are any global_remove events */ + ret = wl_display_roundtrip(c->wl_display); + assert(ret >= 0); + + /* yield the control back to the compositor so it can check + * whether the global is withdrawn */ + assert(stop_display(c, 1) >= 0); + + wl_registry_destroy(registry); + + client_disconnect(c); +} + +static void +mark_global_withdrawn(struct wl_global *global) +{ + bool *withdrawn = wl_global_get_user_data(global); + + *withdrawn = true; +} + +TEST(ack_global_remove) +{ + struct display *d; + struct wl_global *seat; + struct wl_global *fixes; + bool withdrawn = false; + + d = display_create(); + + fixes = wl_global_create(d->wl_display, &wl_fixes_interface, + 2, NULL, bind_fixes); + + seat = wl_global_create(d->wl_display, &wl_seat_interface, + 1, &withdrawn, NULL); + + wl_global_set_withdrawn_listener(seat, mark_global_withdrawn); + + client_create(d, ack_global_remove_client, + ®istry_ack_global_remove_listener); + + display_run(d); + assert(!withdrawn); + + wl_global_remove(seat); + + /* the global will be marked as withdrawn after the client + * acknowledges the wl_registry.global_remove event */ + display_resume(d); + assert(withdrawn); + + /* the global will be still marked as withdrawn even after + * the client disconnects */ + display_resume(d); + assert(withdrawn); + + wl_global_destroy(seat); + wl_global_destroy(fixes); + + display_destroy(d); +} + +static struct wl_registry_listener registry_no_ack_global_remove_listener = { + .global = registry_handle_global_noop, + .global_remove = registry_handle_global_remove_noop, +}; + +TEST(no_ack_global_remove) +{ + struct display *d; + struct wl_global *seat; + struct wl_global *fixes; + bool withdrawn = false; + + d = display_create(); + + fixes = wl_global_create(d->wl_display, &wl_fixes_interface, + 2, NULL, bind_fixes); + + seat = wl_global_create(d->wl_display, &wl_seat_interface, + 1, &withdrawn, NULL); + + wl_global_set_withdrawn_listener(seat, mark_global_withdrawn); + + client_create(d, ack_global_remove_client, + ®istry_no_ack_global_remove_listener); + + display_run(d); + assert(!withdrawn); + + wl_global_remove(seat); + + /* if the client does not ack the wl_registry.global_remove event, + * the global will not be marked as withdrawn */ + display_resume(d); + assert(!withdrawn); + + /* when the client disconnects, the wl_registry.global_remove will + * be implicitly acknowledged and the global can be destroyed then */ + display_resume(d); + assert(withdrawn); + + wl_global_destroy(seat); + wl_global_destroy(fixes); + + display_destroy(d); +} + +TEST(global_remove_without_clients) +{ + struct display *d; + struct wl_global *global; + bool withdrawn = false; + + d = display_create(); + + global = wl_global_create(d->wl_display, &wl_seat_interface, + 1, &withdrawn, NULL); + + wl_global_set_withdrawn_listener(global, mark_global_withdrawn); + + /* if there are no clients at all, the global can be destroyed + * immediately */ + wl_global_remove(global); + assert(withdrawn); + + wl_global_destroy(global); + + display_destroy(d); +} + static void dispatch_single_read_events(struct wl_display *d) { diff --git a/tests/test-compositor.c b/tests/test-compositor.c index f412fe6e..c45d3f17 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -491,14 +491,15 @@ registry_handle_globals(void *data, struct wl_registry *registry, { struct client *c = data; - if (strcmp(intf, "test") != 0) - return; + if (strcmp(intf, "test") == 0) { + c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver); + assert(c->tc && "Failed binding to registry"); - c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver); - assert(c->tc && "Failed binding to registry"); - - wl_proxy_add_listener((struct wl_proxy *) c->tc, - (void *) &tc_listener, c); + wl_proxy_add_listener((struct wl_proxy *) c->tc, + (void *) &tc_listener, c); + } else if (strcmp(intf, wl_fixes_interface.name) == 0) { + c->wl_fixes = wl_registry_bind(registry, id, &wl_fixes_interface, 2); + } } static const struct wl_registry_listener registry_listener = @@ -524,6 +525,9 @@ struct client *client_connect(void) wl_display_roundtrip(c->wl_display); assert(c->tc); + if (c->wl_fixes) { + wl_fixes_destroy_registry(c->wl_fixes, reg); + } wl_registry_destroy(reg); return c; @@ -556,6 +560,10 @@ client_disconnect(struct client *c) /* check for errors */ check_error(c->wl_display); + if (c->wl_fixes) { + wl_fixes_destroy(c->wl_fixes); + } + wl_proxy_destroy((struct wl_proxy *) c->tc); wl_display_disconnect(c->wl_display); free(c); diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 662a81c3..4d94f3fb 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -66,6 +66,7 @@ struct display { * filled. */ struct client { struct wl_display *wl_display; + struct wl_fixes *wl_fixes; struct test_compositor *tc; atomic_bool display_stopped; From 44b26e34e510e4f31266a1e8a85986d437d0e781 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sat, 14 Mar 2026 11:03:26 +0200 Subject: [PATCH 1151/1152] Send wl_registry.global_remove to global's offer list Since the globals track the registries that received global announcements, we can use that instead of going through all present registries and duplicate some filtering logic. Signed-off-by: Vlad Zahorodnii --- src/wayland-server.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 932ac662..31b597e4 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -130,7 +130,7 @@ struct wl_global { wl_global_bind_func_t bind; wl_global_withdrawn_func_t withdrawn; struct wl_list link; - bool removed; + bool unpublished; }; struct wl_global_offer { @@ -1115,8 +1115,8 @@ display_sync(struct wl_client *client, } static void -wl_global_announce(struct wl_global *global, - struct wl_resource *registry_resource) +wl_global_publish(struct wl_global *global, + struct wl_resource *registry_resource) { struct wl_global_offer *offer; struct wl_registry *registry = registry_resource->data; @@ -1154,7 +1154,7 @@ wl_global_offer_done(struct wl_global_offer *offer) wl_global_offer_destroy(offer); - if (global->removed && global->withdrawn && wl_list_empty(&global->offer_list)) + if (global->unpublished && global->withdrawn && wl_list_empty(&global->offer_list)) global->withdrawn(global); } @@ -1220,8 +1220,8 @@ display_get_registry(struct wl_client *client, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) - if (wl_global_is_visible(client, global) && !global->removed) - wl_global_announce(global, registry_resource); + if (wl_global_is_visible(client, global) && !global->unpublished) + wl_global_publish(global, registry_resource); } static const struct wl_display_interface display_interface = { @@ -1488,29 +1488,27 @@ wl_global_create(struct wl_display *display, global->data = data; global->bind = bind; global->withdrawn = NULL; - global->removed = false; + global->unpublished = false; wl_list_insert(display->global_list.prev, &global->link); wl_list_init(&global->offer_list); wl_list_for_each(resource, &display->registry_resource_list, link) if (wl_global_is_visible(resource->client, global)) - wl_global_announce(global, resource); + wl_global_publish(global, resource); return global; } static void -wl_global_send_removed(struct wl_global *global) +wl_global_unpublish(struct wl_global *global) { - struct wl_display *display = global->display; - struct wl_resource *resource; + struct wl_global_offer *offer; - wl_list_for_each(resource, &display->registry_resource_list, link) - if (wl_global_is_visible(resource->client, global)) - wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, - global->name); + wl_list_for_each(offer, &global->offer_list, global_link) + wl_resource_post_event(offer->registry_resource, + WL_REGISTRY_GLOBAL_REMOVE, global->name); - global->removed = true; + global->unpublished = true; } /** Remove the global @@ -1554,12 +1552,12 @@ wl_global_send_removed(struct wl_global *global) WL_EXPORT void wl_global_remove(struct wl_global *global) { - if (global->removed) + if (global->unpublished) wl_abort("wl_global_remove: called twice on the same " "global '%s#%"PRIu32"'", global->interface->name, global->name); - wl_global_send_removed(global); + wl_global_unpublish(global); if (global->withdrawn && wl_list_empty(&global->offer_list)) global->withdrawn(global); @@ -1597,8 +1595,8 @@ wl_global_destroy(struct wl_global *global) { struct wl_global_offer *offer; - if (!global->removed) - wl_global_send_removed(global); + if (!global->unpublished) + wl_global_unpublish(global); wl_list_remove(&global->link); @@ -2889,7 +2887,7 @@ wl_fixes_handle_ack_global_remove(struct wl_resource *fixes_resource, return; } - if (!offer->global->removed) { + if (!offer->global->unpublished) { wl_resource_post_error(fixes_resource, WL_FIXES_ERROR_INVALID_ACK_REMOVE, "global %u is not removed", global_name); return; From e647f6304d7491fa436047908dc559f5badf613e Mon Sep 17 00:00:00 2001 From: YaNing Lu Date: Thu, 26 Mar 2026 16:38:38 +0800 Subject: [PATCH 1152/1152] util: fix use-after-free in for_each_helper for_each_helper caches the entries->data pointer and array size before iterating. If a compositor calls wl_client_for_each_resource() and the provided callback triggers the creation of a new client object, the underlying wl_array may be reallocated via realloc(). When this happens, the cached start pointer becomes dangling. Subsequent iterations will read from the freed memory block, causing already-destroyed resources to be destroyed a second time (e.g., leading to a double-free crash in wl_list_remove()). Fix this by dynamically re-fetching entries->data and entries->size on every loop iteration, ensuring the iterator always accesses the valid live array. Signed-off-by: YaNing Lu --- src/wayland-util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/wayland-util.c b/src/wayland-util.c index f5518676..15e157d7 100644 --- a/src/wayland-util.c +++ b/src/wayland-util.c @@ -424,10 +424,12 @@ for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) union map_entry entry, *start; size_t count; - start = (union map_entry *) entries->data; - count = entries->size / sizeof(union map_entry); + for (size_t idx = 0; ; idx++) { + count = entries->size / sizeof(union map_entry); + if (idx >= count) + break; - for (size_t idx = 0; idx < count; idx++) { + start = (union map_entry *) entries->data; entry = start[idx]; if (entry.data && !map_entry_is_free(entry)) { ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry));

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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case1-2.png b/doc/book/src/images/content-updates/sync-subsurf-case1-2.png new file mode 100644 index 0000000000000000000000000000000000000000..6839b679990902c4ae4a4a5e092244d74b853ee7 GIT binary patch literal 27535 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case1-3.png b/doc/book/src/images/content-updates/sync-subsurf-case1-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9810a028186cba6b1578637834e7a5842fef9aaa GIT binary patch literal 22771 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 BZ`c3; literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case1-4.png b/doc/book/src/images/content-updates/sync-subsurf-case1-4.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3c04bcf0fc93b0661a475aaa02b7f7821bb734 GIT binary patch literal 22017 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case1-5.png b/doc/book/src/images/content-updates/sync-subsurf-case1-5.png new file mode 100644 index 0000000000000000000000000000000000000000..1b2ebc3b1dd53819002152d9f8d77413bdefec79 GIT binary patch literal 10932 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMiGhJ(ugZlq1_lO&WRD&6h2cL4F4((#G6Mqxdx@v7 zEBh-(0Zs#%OHcMjFfhpYc)B=-RNQ)dw=yC){2u!U=C+BdTe&0-ta9P-W}U9ox7Af^ z2?tk3dItMOU4^{R75Ro`UGEz_I$OhCW$t*b-m>6PP^Ne4MJvHK7K_*V#kfTY2)qbk zk7QBN=o`a5@?KY8-+UGRR}@AGy`l$4eVGB5;8UAWAgfx%(B zq8lT_3I#e41txnL4I+wm#%N8QHhuc_t5>&f-!3gJ{kg)1ot@p>+}zmM*f(GHRqI4< z!&Pse6jg?Wh57mQxhTC{-5a36!^OqL%X_uCMl$njlbpeeSFbL8G2>bDrJ?bcRe9XX zrPU4#13HdAnleRXrjOZ-Z!vn|Dndt(9V@c1`dNQ`VwnC5-npHD>HoE}URvIdwN5tC z*VnhQ+O=rWqs;vp0vtiX!OTodCb5jKS|>6YuIe?MHD}JA%*)H>y?!hEc5cj^HR=(w zXGm<{y7l_KwYu7xtM`Q7+?*N|6y)R6v+T9QUIV2E86K~5Zf()Dw4Ay3Skj)Omo_B) zSE#?Oxy|mM&G*)bzZ3bwS*PdWqhw>ls^~@6b^)N~%3m zrM#H&U;Fi&D?PmZPT!b)FmC1FZ#=_ign-oeC1^Iq}{1rFV6;vXJ4OJe>DC4 z=GkXU=Fi;o{N&1GU0qxoBi6ip6tZ%$a6%-yfN8c+Y94&g7Gu zHf{R#^Xn@R$jV*){mDd`$kk^qT=?+hrv5&w?@v!|j+c;<+O~b`^OSneNc{sBf(+fh zzrQapDS7ka#f^D)t=QSy&zw1PJ-&XfK+)e{UtPP!?(Qgj{C4~OZ=XL~SASd6-|z42 z%&hoi_4<8Lo6~%QgM%F$9GsnrckXXEP z=gyW1&FuW|ZftyfXJ>I;U0w3Ap3JN)EghXVFJ1_Ay6i50f9~A5y8nN_r=Oh_8W!fp z@$=2*^Bjuq{c^U2kB-c#c%?ms{5?e+Cj??mkkw7GcfmH&U?kB`^hK7H-)%Ij&m z{3+gtT#bINk2YKPGDKtA+TX#sv5$lQ&-iunY0BdR}oxv1N_+2HP0!EdeQm)qReOUMT(}M&5W91Xmf8RNK=~VL0`(bok=- zBz!xwa&dj~mwV5qd|EYsZKc?(d(ZD~JYRjo`quZVvzEqO*}0i#|5ya?e0FN7_UZcl ze?0y@TzPrfx14=R#m(_ zG{N(a=l&~yKFz+kpEFi=S3zg|`nSJVi96g4k?B2l^ytl7x8_-up1OK9R6*d#(W9oO zrh-n>bfcd=eHt1T_U!H3+|<;qNk_XbUAmNa|L*qu_^2qU{^Q+UT|sZJ$ItzKn_084 zY}?}|FMQ#9?^^kD^38O0 z@#Xtwm6nwi9WOZECp~+@q=1sQcdprY^YZdqTUmX}yMO(9_>H|&r%(T0#c}@m=f{s9 zuU@t4+4=eFL%&K%Nchb7BXfS%^@|q+D_4Jdc(^_JcyDbQ&-VHAc3-u&dCIUtVlh+W zf+b5-Y;9{VE^;k@cSo@M=;rkEd6}7#wpCkPlun*KTl;$Lb{<|{Vkdt zXlQ6?WHjmcg3dP&>(7K($R!hw!dx$7WVA;7x!1){qq07(x(SH{b$dfRo)eB?`v%^qv~e0 zsKeTj`76y04I}qfmDbh$n`>SE?99yI$jFs8>+fH^y0zltBjRkQFzc2pv zFSCCyAo1&-eSOs{b`IX=Z{NzU#hJ?e5m&$Ir_%CA>-X06Y;W%Us;pVg_BHsuc)P!l z(=*QJd*6KBw6XJJ%=w+4Yo7@_75P8mTW0<(jx|6#G-=DmjT6s5_n&35a_7#O0!ev! zcFD(hoH`aRe0Zpp+tyO^z z#hZ-{bbjUK?tOCPpM(7QeY0ZsMv84NEkDhC^O7oe(*5X*|28-mJ!JQN{~=C7+WzP9 z``4~LxBu5%ZETi*W6sonPlD#XIwj?FqC)%hzI}(@`D%z{?Yh9YZNuzmzkN^r@0ww{ z*iBN%DQZ>}+hytM^-L?KY6bgeklQigF!& zd3kwlP0gRbf8BefLIVO45)uT2gq%16?Timyxl(dTZ~Xj$*}~)b|ATL@2(-4do1(w-!?X9|b+x-@ z2pA==TD+{hLchXBZgWia_HFCap4#8FDm6NPkB%`{IWZE_FeDZaKEU5#Z-4XVjj+03kFKF zOiWGhZp{vNbZneBapLOLui52m9=v|-&9QRrTGf_2dn!LaJ3IT7UrbC)$nUS4x}=;= z{OrE;S^U58^ViS6UOL=&Zd%yQ$H)EiCd~h~=fMZLkL}j>z8*i1%u3%`e41_j^t+~e z4_7~Y@IggNxi=e9R7H`SlByWr82&hmey%lEFGn|!46SMn2u z*RpL<3}4<}RFU%ztNBy^|Mjb!|01^82N!!jDYBgYJLTQ#2T67D*BP$fS$A`P@&Bpa z|1(x(8*De3zyHD16TK79+_kEU}-%68{A?~|3amQ;d-(2Ds5FoI*M(1-y`tqhthtK&P-FW8l-f!oZ@myZD zO6#d@T2;J$gVl?a7cb^txDfEnV*AE@hPsx$n+|VzV)9H@I!4dj#AM6-V~5T7u1>0A zY!gcg(Vj7LW~YmPp3;dMvja<(c|5(>bxvgC{dI~$om<{=lrOo;{mXa#vKb*SBe|E& znBsQp@&os%y$g;TNL>|^;Zrv?o%&NFd+K`5$j@7nw=6PtedD9pvSit^tn_6)phlsh z+g1+;2ZrCG2RDUPhTPb#*=fyg%zXLgN)OLFlA_=Atb->_nzZHT-#q2DaTmfZR$QOf zTy<>1p6#)fw`ch6*p51U&so|~Hw{K5+o6?63#a7OG)4i8o`t<43n>RU~ zE=Jkcbe?8M-o10@i;?e)s@Jbx-MW3dx3{;_W}e)2?p@r5tEzc;c&3yWgoTD?Rz))~ zTg{p00oW%QFTBx5c~MEJZ>OHHbJ!Cz!1A-nI7?Gjk9_Zo|bDdWrn5 zQwKQSwTD^Me%ahMP-&{XwzJ2|^A_plkv9Q?K zwJ*=INGvSK3rW{#o^<}XvAXB(UAwxvyMNaF`>=m9AA>|k;N8Q0fxh|N3=bB_F*NWc zi7+&94PwImvNS`p>h#k~gEA{CEjOzvD<3|1@Zj0ApzL@#n%$sCvZS;$vr2k_ebG)E zZEbCJb$6wSU#_}oh_JD;wzjn?`7^f7&pVRwl9Bmq>AO8a-rpOX77BD9)zs89nwewp zc4y2w50$Ro-lqix6BrF@O4Quu{$0Of>GPWMw>=m4?Ai0;#fz@4uH}ChIVgDe`tovc zTqt2>P-bn@y`^DkS$TPxukH2Q*0-#8T15J9Ff%mF%g$cEH##~jD6Dezq`S)&EmATt zFwoT0R8w=iT*}bH(Gj?IbLQn`PoAWFlj{B`=6$&7Z}Xqr=W|7J zt@7^4)22;ZvP8u3LZpF{4rSiV%>X{`aTbveNC@Ez4#bdZi z_ehdqb(~$L|0kdCGvBbScD}YFV)wT{(XyM`?&d7}eddX+f8SGWEv+L-8<%x6Ur6r= zT&pnsbZ}76jDEq1g8tTgsh>Z6O`5On>*+c1^wU{-f)4pB&A_o z{QT?JuMb~0-9u&Gym`sT`%KNv<2NKUhG?bMdn-+pkdUyjw$9#F@OIMFsYhdy^9}DM z)t>n^FSo2_&)+}2NzeS1{+?F(r{Z+N=6xl4N6sWxso@@39kk|8@}ECGK7POAG4IxE zmoMIY`Q&4DGv~YdpRf66-CV47^5n_HY17+SzgsOgd3MuqnvM4}{qIN2|F8NteedGG zo1QA#N=w6fVhlXGqU)v4o;|DDB4blgaBoi~SF4hN!GyyPO-xNi#l*@=N{$>mcI@a; zK_@l8ITdejZQZoV$lKeSpTGb0_4Vv*Z1b#2y=uR{`Sm3u^{l?s?YUYLPd|P0`|022 zKkR=_>6`9f^4?3m<%r6$o<}{ew)WOf_o~|Id$sP%IfOq z$jG%38y9Wa67qBEi4!MUxy4s)onhZ~InB4cPWeM9?;8)UH|h5+cUth?_;>4R_9Q1x z#gw%fx&L)_yPft%D4mf#VFW!FM@3;5*OWwPE+O^9n?PgWe*M_(DxBp8j zro8&Hve@R?m;00MO8*XLNZ?p$7o4Azw5jUrt3QAKSeL&$Gt+qarcFVX{TFdG>dPhj zF<*Imp0 zW+u!wp~bzuy)}0AmzH>*J$trApt$(6q;Z;n6Av%1xL!;~Qc}^!N3KpB?S}*B^%$Fk z{Jy%9KjqVE^V4?cPDwt0^EE6)M)Aqkr;8rnuUS2F?yo65z4KdQqi-`LmcRS5^LW3U zuv1*D$%mcXW%+O785``!e6z&)&YR{r~Upp+ipI-rn)?@vTmU zzrJM3%gfi-{|{X3CMqH#AtBMy(jwqw_y5o5uCA_a+svFioSmI>a�`%*@I>{#6$H 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 M)78&qol`;+0Ak{N+5i9m literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case2-1.png b/doc/book/src/images/content-updates/sync-subsurf-case2-1.png new file mode 100644 index 0000000000000000000000000000000000000000..25408cfcc4290ab9bb830824518b0a46cd1bd789 GIT binary patch literal 26210 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 bpI!d8_sP5e^D`M37#KWV{an^LB{Ts5gHhMH literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case2-2.png b/doc/book/src/images/content-updates/sync-subsurf-case2-2.png new file mode 100644 index 0000000000000000000000000000000000000000..63ea066cf2e69d339936f24f6900908606bbca55 GIT binary patch literal 25821 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ℜ7d?Pq?wI(mT9(FY?nw;T~il_FJxnl)A^@` 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-subsurf-case2-3.png b/doc/book/src/images/content-updates/sync-subsurf-case2-3.png new file mode 100644 index 0000000000000000000000000000000000000000..3948988d51cf3f2f671bdfe53e81f9b6d1ba1ec3 GIT binary patch literal 10069 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 I&MBb@0KaK6BLDyZ literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-to-desync-subsurf-1.png b/doc/book/src/images/content-updates/sync-to-desync-subsurf-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3a56f260a12df2c07b0d95f2bedd518f2d4cb061 GIT binary patch literal 18621 zcmeAS@N?(olHy`uVBq!ia0y~yU_8XY!0?NMiGhJ(ugZlq1_lO&WRD&6h2cL4F4((#G6Mqxdx@v7 zEBh-(0Zs#%OHcMjFfiB)c)B=-RNQ(yx4I(a>dyby=iRJMnpvXCWf}@Z_=T*0r zQHrdKnwV~hX*UVvg?2AE-|yDn$;Q~J7Mc_#x?-M~B1fF1uF`_7mJQdp-4d}0>f}tD zB;cdKx%13~nYDlaems;^nkJ-XTs?zl-~8qL=jY8e&0fDXdtc@CsQ0axO?nkLniLKu zb$nqEU~ya|JtdIEal!-#Nml_DPEHh#-6iH7DIbd(A6UG5WWQ^9yIVmHN72hhqgBQs z3r&1KTiB%Sw%k!yvvjTcb(4&f|GqT&4aTJdMw!b|sepHt#E)MT_ude*YJ5ygvMo>cp`EJS^0R?M_O zvF3vb1`@ZnZQIC|?PYv$f6!i++rmyk|7UQe=^QUS*L?2P%B%bOcfV;q?cizIm#v-u zJMV4zzFf9@#uswT4==Xo@wsZzek>}-n?Q7$0OEL zE9^36UE8$usJCgA&VT;%;lEs*=`yZ&-lakv%k%>(&jih?nnisxynEpR-X~ra#k2dQwr83I>|9-IHSJRc1R(w+OGt;SK)vA-L zCpo4&ItO|Rwy>s#uqSZxSczI|Ui*{0dDW^_tBMX=I(eL#BM~U#SlgrAv-rR5t>D*% z*LRuvUN-T~44Cq`D@I?~>CXHeoQi)u?7ppw2o$NDXD-20_w;<#_N#BpKHKPXG+oT- znJc1g<&wNAFf{aVLG!9rEdrnW&&u_?3$QqGod4`BCvQ}6&%re?C30G-?_M#^E0QvPK}(FXyCT^Vur~g-!6r?1wF5rR|qK{nUS?+-IlIJD>S-R zt&%x@a#N0hgu@ITHs<-KCNDfD}cXRE?K2KorL2uul-O(>lppmhDTf}ui$4Rf^%bI{Vi>RaSj?RQ%&xU2Q8 zx7O~Ee;M1iq`#OJ7aU>vta9EdjnI_)th+BQxL_Id*!RV5sk`W+;%vTIp6&6@D<{TGJm zpBo<+?bOoNUcGv?|2&(QWxI97yn}**+}zy4!lqr#x>~N6)5UONkGQd6+gHXN9DM%b z#rrsflr$Fqa^NppV#Rqby=0>F^wXhnar=s&pX=)Cns@8TlP729*;<>Mhr8D%+P)Qa zZ43$8yTj+D>yl^P3JV2f)xWy`7jV0sen;QAig|&B`n5S3ao2gu-Q?slx6Q6)HvHY9 zbK2F_b?MTje#?y~d^4M^tFOO)!v=vzj?Qx?u3FW1wC`K)+m;Cj&+~7)n=5=yaM{@| zj&tIUPAXadgk{VhcNdgYmz>|au>6sz>dTK69qkt~RPUSki9fkpem{0+QL3-6?}PY4 ztGU_N*WKM$TOApB^UO?R=lO!Xr!{iVf+&$X`$ zzWHc9Ha2qeqV}^zo9=Y;b%v+uqgv*ZCSj zm5iS3Yil~cNa*=^KfQIt@O$gh=dY#pG#|G5Lcmz&j`=QN(}7k{v_ z*3@uM0fS_PfkAS%E{WTh+|$T8`P~x*vN#yxaZ$+$_`Xx-GmLrtOI^O1(AZ0Q=_u zfB*i}{xmmMuPXifySue_&6jLkJHh+@+p^P}&J@l$nX)NDXToMLamlyppIs+haFo32 z?v@%^w)<}0cIj8SA8hhBMmUr+O$>~jroaDBQPr^|>4e&sTc@wv_wCibzULRj+uzNv zwhx{5<;$1#`~U6of9~|AN5Q*ck%r81$9wjZPcAv_S^Iycep3q{TXP%B>`p$WSB}|x zF5QjaFn`e^rEha~Jvl10e^$|+cR!k}i;gc(>GMCi#_rYfSD&t4kBj~E=;zvFvu4d& zv}n(nzfKRXkNf%k)V=E2M!BaZ zJ@tNZ{L-bM>8D+PaU3svyMEhl`$FsZ@=H35Rjp~PM)x0=9)G{D^xZo1`l zzwUc~=c9eO@9fKe?w%|-Bkt&=SRr|LM`3bWT3Sxdn+pq_#dV`fUR}}L5g!;haqe7M zd3pPa4-caAb}rrY>CgJVr}g*Sl)bres-8T z_We^b`=(5v9z6eZiy|lgQ~M{kpUKbvlYCY=+gI)K`RD)MG&NUh{9o9j$XW2V#On0v z)76=83M^#!+TZ_eTguy)*|#j-bfR&G5gW{+oAs=uP*Pm z4RzpnneqO{@8x?H&xt#hsC!7>-I96v)6>(gfi({r*^P{hw&mTedOo*Y$cazhuI6^` z_S&CMr*n(x%&@Ed#V%h{@cFFy_AOfkoc?`TZhyD_|KH{Q^XFL>r+Isy?h@55dvinZ z<;&O1#|zg+M@zrYU9*4dzuO=0m%V$zW8*ESnDYGG+%Lc0wHC7+Jb!K8B8}~5_N0Dy zfB)o8*=1I15te`NT8saDJO8M_;@X->mL_6d0cPQtKwa{uv*{omO9hS_eWL= z&;M~&c&YyS^Sku26Yd$am{=V8p8e(E%>!P-H2^b|E>2Pl63k?lbRa4vd>6CWMgzItDy6WoBzg~}@ zZ(aVb`u$$>{Cj&m_A}Nph|yvewuLJi~{Fx zyp8?o$KFUvU(0WK-POf4{q#|{1=ccsy3yMLzS_v;Oiczy7zhV#<>f6DQ8wXO}TcZ3$%`}k>w`S%63uPh`X%39e?CXx5O?kGdac}$TQ3Y3XP)s-O?|q=b8-#qmg$lgvppv* z=<5h~obrI9VBeHC+Vz*JR!x1pgVQ`__n(PRll9KOxLhOnL`mSu`Xj4CS6{kxsqFo| zxie?ZoHuV@*40&)m-`DlJv%$wJoVI+RjXF53|_9LuC5=u>&uIai{tL!-BI}X^LhLE zQ>JW5I@;yoA1|MgTUDpx&mkzAzPj_oCZ5v|bDOLHVdoyH0ZC3-u|vreV&J(-@nuG|0YeEB=qv->$dQ@DK`!^2Py4+eeUGs z=l%17+g|>3x^b`U&5eyEFN5xz@wF$vy|q=`!0&n6>!qwl_xJyK{P)}Cx7Gjmtp9TI z(xgz;w9PNq-Px^oL;81^pvoPV{SMuoojc#}`~B_B&C54#RNO7SE^A%Jv+bLy@9w|f zZg0=MUH0fmXX@!`rRC-OKOExzAbR1#nKNhh|Nr~m{>MRnCEN157fgI5GzFZdu(dw> z)Ue?fx7*^~ck`Z2jVh55y&bLp(pvch>+{vCR;eDFWTcaNlDT{Hy3Pr(!cZ|GrnNRzGlgdM!G?x3lx-o6YAr6m8BQ{wMNg z+1~H>s{L&~9!Z@Z`|V-7{IaD>SwG(S*KhbWhtcBx<+t-TM4bEosl5F4&(r6>O`AMf z_+@!u!-lVjz)_6+Z49Glth798fyzP|44nKLc9JMRDcwmrW7?^Xql@R-7*i~H@kBsGG9f@aO0ebet) zzx@BJ;qk1WcGO7+zh7#7_wL;Zrw=C>G`x$@nRd_nYWLQ^P=4D&eQLj z^>?E`etGOK=wy?(@o$N>#k$XXCJKByC@z1&=!DMp^!twf>+Ju0I2`Bq>fwUSi;G-K zthyF;Ja4GFD6rt_?-(Y<13%?{Kf5vKWqJAhmudOOqLSn9e+Lx>f9sCE2W9Stm7ZTF z2F?=dJo_}!Y_`6H=&PcgIcCy-cYNP$TUXmqwtug6y=&urxqUWuH%?Ta&WO#un`=I& z{A7vM+`T_~g`Bdov)`6kf0b^v=b5B(aud%wzX_`A{S#Rio|!K2$l}?JFL&Pa*Zy0- z?ENhEW4v<;4!5w&#Z9v_yPN;`-t%sSMAqVmFBp8EC~`36^c=cYpzu0=_0?IECp-5y ze0y`}^MS+sKg?#AK3@}Aeol#TbNX|+s=1RVKVGU?w!8N1EYof=T_(fWEg6Ct8gu!M z7v7aGmv)mlCu3t=aL-{|TuDdbSH^SG1(M`*|DSD}#IXBq?LH2nFauN16#=P+QoUJ= zxeUK<_{UoyUHI+I%`d;cuFdzDB=cy3if3KzYw5b*>5PVJ*RE}4Ft(CiA^!L6+56XG z;x2z#t@d=sqV5K_ntdEXY5{Iv8z1jjZ@h2a?6~U%(an$9`94VS29y^S7r(UH{x#(F zXVvrV7BilE&s%P4mSYy3mzSsC8)-dd*S>HC*4yvt;OS*OcS+{~> zlhG>vS<7Z#^7*3d!M`@E{NQ?VF|lRK=iA$yjGtKlqTAV#=kW#c_D|t+)=!){Z(dwP zgv61UJ+EA=ZRBS3#j#KNn+5HOJXorqw>?_K)pHWlmIoE{^tH7Y%g>En_xt(1`{B~L z|9}6!*(KF7Vbi8f3R+n)7o>RqmVRCRQ^})aK~G!P{R014vs4PW^PZiVnbVn&K0W*B zA$ITUw&Eu^dsI#?eLXLF;|IsE;I8iO<`wDBtA$?~UCia$doQ|vhJMovrc*2O9M;(! z&|YSDK**otSDt+uURgapN*EpMb726D-Wiw_-L?v4mclq|+FI|GKPSldxemE#5My9K6)7M3=flt~BZO$J*0s<^?`c?%>7V#_> zS*HZvO}P^J_RWv`eBZa{nYxPBsc|$3NK1P!UGDEU{r$e*?@mqCzIkgV;=;nj zzTCQ&zc<78@}5_&ub(W>;_UzRoeb3%(vt{=(Oq_gd*Sv7n=et!8 z>N_?Ytzr(TT9Gf{(I4LWJwWautm|6-=0;#(VBuNQ>khux)~wN~y~^_J(Yn&|ckiDB zS3Y-4cXDJpa^<_GiMGp&8su)S1>@|ku7dt8?VZK?msKwyM8_E@oB#}Ry)2jUuHKU=_1FczbtD5YZoki z#i%Mm=1ad?z-sSjRc;)H| zeb-h@*W_xss<8BWfD-F>H^C+97o@JTYZ+eKy*8lR^SI6NI^RGAA2!X|U;3qwEo@No z&|hG>%J`U|TUcR9$ zDyGyB^Cwj^1s0iT}9#nqMVE5byASw6D%&p6cdu71v+EY*m`yOv3vn*CG!WrsLm#sjYFE;LSWGP?q7M$?db8tekTF?2Bf+X!J4h z(%QOarD>Ldgu(*5T|L<>J2@8gv~k%^W{mfa`lwsgziscDz^5`Z9&$SVY05UKU0}qe z_j-E6ekEOfon8x_Rarv%=$D7$QUQSs0si6a&3z(m(?8+hYM@2lE47EW!A#lH?%MXg%p zb$N=*`ktVkmB+l3CyRr^FJr}pyZ#z+Pplqv?N;XtnJTuqTS;|k=S<(S;7i9;4zn;z zdMVt@5XtpbIB}FEHAMc_soSrnU*XPd3Q;eVG0!--V1;miSk$U}k3XK+1D?W9~zCMwD#3a*`#xMMpg4cfxRm| z6>7CssMqwYi&Qvql(Ckfv|-l#1{F`ae)mZ#k<%7`X_!52)%&Wo-qs60+MHje=4j|D zAT}lNFJpGdB$W@sU0(`*@z|PV$6dcuk-zxTf(2Eea--)}Lw=jORIvP2Kc@{>U)#L6 zBC)8-jYEj9AU{O@M$oKV^+GQfwi>K7VO*ws+NiYRkcJw|N2b&ed7rY&6L_6Zm>&7N zcJ}UR$(>&=G`0NWZD0=X~eJbNh>L>RJ-OQ&}*d5T^rod5<#eaQz+x}f4`i@;Ti!Vy-ja(t9QUee$Y&I=83tSc(y6lfc_V`!_#ts1|3m zDLiCYdoh5~*msTa>SG}XWjEiIvDP$Ob=hq530|XB>P=smPOY%pp!K-0LdQJH!8!4- z^e?R&Pm4ms!otGCFI&$x&p&tK#EDape%Ef?>pBVx1TUuIfPCtL{?Afca{tuVLWd`WoyX`VTqotec_oEl`hjwVl zeLp?n9>a}{u0=JOzl7c$nR=9WhP8tL%jTOhC44oJ)4IF5yu7{V`lTzp%{7aTi;GK4 zR9w=>SL?QF)vm0Vwb4;)wbxEKe?P@&=GnB#CtW_TX#4d_@W~{Ftdx>FJ^F_(eV&(H z3L0JefBsK>!SQYP#Hz#B+|1b)p_8`Rvg7lw^82;rPftxXH8ri3^{J|=f{v%o5#-JM zT4A$DBS^CKvhkEamc)aud-)pPeNe948Mln-$mg1Zt#`e>ytufyYTozD8CSjeu~GAI zP*Rf4-MjCW3Hye+uj;EU?#T@f4mQrdw&u~JM}PkOS+LyMyg2hz;Hzr+tN)_Gt=Q7T zQ_`3uzkU*U6|Bz6%BrfW`ets6B4@e&9OL9~JzD}Z_q~0c^%~S7|8>ng%75#oxg{kf zBI4rhMzXV#MVMwrNV*1#I7VE^4`Fu*4yv0!>C1AJ+f}ol`gs==1qTH^TDs7Cn*Pca zYbqW*WdD<;p{SA@a*LVYJ|Hl1W6IA-_jYqJH6MKN@5tS-OUukw*_>Z&+NDtEm>nXo zu*S~J^4bsO#X6_2lyTq5{BpPae(Lp4+ZeA+68B!_Gh66HIcwwj=&!HW$p1B{cip%7 zG^;r`7nhN-aq~U(rxxp~vbKI+ApA}HOj+@g`-V+lfRI{(x=PG{$@TdVip+Ol=a+SBpoe}6@9eskSt|G#Tj z`PWx}d=c!k z_w-XOUEQVf({Ww)2je|hfj%R|?<@45IOCx6 zU3Fbu-O`;gwX?d{?|oTVv1souk*1dZ2dO2GkM+)+IdkL2jn3_Sv0E}Ot_)uOpw89R zwXCeHrsmIsgU$InpH4e<%IjOSsHmvS@m^_jy-UK^B`2Jo?5e(h_y677CYh~Y^=_|r zW@V-2*Ny%XlRgCebKaMG@7A}lTwmSeg|FkI{=dBFe{Eg7Gl%8Pl23EDm;E-YLm9UG zZ6&KO&%DylDO<#`N{P%d$OG>`OXu(T*d6~z=~D1DdHty(uU$Hr7Ny0$-?h2;xnEW7 z_d}LV51!vyzx#IW<0;b5b>>eJVlP7^5Fv+m&bjS3&i_2)d^{@?Ck zTE(KPOPS_~G}Y8|d|E=rFrwcai;o{39^RaG_SW9&@&f+1|06c9UB@3gYnkUHm;RU4 z=Ox}3?YvR(Q*v|qkKD5V|9AKQt=O~gW6x_IMHNlelli|TH>c-B>=#_8t)&&C7ap(t z&eV7DybX5>_`Gi^dib+wE1g=Qf_sFKbGl)m-g0VLZ20)w8L?bN$u5`frvUe_^<|`V)Vu zpzFtv?Q-fZN1~F`|J>RCW?8S7v~8M6Z{eynYv!0_2E{)YH8ynH5ohr4$_lmBFZ8+; zYz3bzs=K->G&3`EclrBsXU_Qe`^Rt1y880+a!$q1&(6*^O7#j2y?SM3@Z`ypr|ZR5 zeR&c1;C)Q(;9K7B2CZFk+iAG6o5UTgN6J34+x^~E{& zszLS@IY#(L%zNJaxy5zDd;WtbGP1K*-_7&)_07%CS8w5wv-z=V^|~g3H_`cfP1V$% zZ9Z?O-15PO|92sy+b0+6IJT&U=LTY@D>uG=_b%{Fif3KHMd#A{*LeLTwmkJ;@3Zfx zy7-%!Z+mOK9$Yq*;5k+3YQ3;@|JAe0PVBysFXs5m{Gg1Xs)~xw9E-x=-`afhqt$PVxpqrk_{USI_`h?#}+zmbLS_iDF?3a@$`J&e`~g%$=54yruwdz`S(20 z>4b9jKW$CRl}}T+?>uLFr)!3UMr&i`6D)etmUy zb@=*ke=qK-1Z9Hf)&JMm|IJ>aE?st}?DLBCZk>xx%(ZXZ+3+GIHTB}__&-bin{RF|=HGkn}%Ed2m?f3zULmnIx zRXjyp*G~vwaSU+#+7fnmL8p7<_XTlNOw7%%r)@r1`g-NH=ic-93suffxAD*Jx{S5;R5F0lx{tp|);FPj`sa=(4e%&FsV?QYZCSr*4xuYcX76JPi9sY$VM%Kqu0EjhTd%W#a%b|`Oi(8jDB6b`E*zPyT7$tJ-_eYKmTfglSgD^WW4E= zqdDgM=j6|P-lKVzW%pi*;C_XD3wmC$X-|J3$1=N<(XI8|9LveNop0V0t&RAR@N(C4 zCd@QB^y3>F(P+ ztBWC}OS-;pOtndr>5qt4d^KRq&-XL<;$0;si_OsJdK=n-E@0yuCQ!UcH!zf3jEcX z606jkeh8TwRh69II#KRWYv){%+aI&o*X|PBl6>LJOylML^W#E7LZYI)R^R>FcQ)C@UeIy_H(PI6yVyrk(-D%893{p8wSh3PgIAAY!Uo-r~oG<4FEb@{t&2dm2(qRhV6`5ck0xs zSFc{lT9<`{gv1n|H4T_-s;%wq{xxOcZNXKm4(*R?Pg}8&gK2^3D*l9CtuCgG&$|{C z$gpplz0c3-LMLRP>wZjvRjK!@TidrDKi6sd`IzLxD#d@j6XG}Ssc%c-d$k$ zbxVa{?4MU(J4~~$9cVrLFk(+dVZ?IhwSk8Vm_=rM(z+!6O}tAXkV)@VY4c-?jea?| zZ!KGu^(eWszlwb*`RA54;1r-hVrs8zw3ppis?59`oOhMUqr-? zHbL-75bN4N*#+$S1!~Nlk4m?=t<=oge*5LwlatlktJ_6hUHNQtf9Jl<#kK0ME9yVS z={0?+4siQ=+~UxR_Y2KTU2g`h;TG3x=`N61vLPY=?yV@(WviaPoHlKFv{iWtTaW;& zyv-`g)Ww^I+k;a5Hkwr5e#7Ot0I@w=gTe#)++bzPrm-%EY61LyIIdxy3 z@gDKnG>Y{3{RTfqXOE{Z9vrDTPB?uI=7iyBr}J~GUivtXWV&5Eg`==Ix!yL>N3JDIjO+T8ht;jQ3pDiY$Adi#iE zPTcomu3%FO=aj&^21{o;xb-UcbS>K8_hzD8)C7l!y|dO7<@E_$-uTdaZ-)*Gr?AH2 zUkBEesd_H@`Jr^>IvLG`KTQe_DjJF`S{(~|lsLFgWvr-J`e4hQ3_(}HmNqMUSJ^9` z+OI@+-k3`Y%2#F+L`k-hCxr>U5liNwYnF zz>Z%?LmrL4 z{grGN1uSP4zf++1%4;ELSZ;0L-3Dc~@9KHCOSgISyP7|Gc6?&uk&5;}5!YGWzl45# zZcwmlGFoMP?25PgA@-zKkKc6`@4g%0$YK;8%M|P^AnPc}Ykg5;<(DZv&la^=MvU$d<>Y(G*Mb9&mewxzruCibp8{?w)^Ai%9uxh!Z+gnCro7MAVuzv}l_>*=W; zwJQ`-OgXW@vAh0T@Q(lI{xQ41e*Jdxrq;&7`rluKZ`FN%c2-hSGBPqUZ1q>AGk$A? zLql7?tYpyAY+~49b(y{I@g%OvZ{lwyKD`~j|Ker$eMR%FSf#u;CZ_D%xpnK#tzXyA z|GReQ*00Cp<9s#l}oWo!REb!n;h=FOXP&2IaegO($yO+UT#_mUgAT%n<=o|964 z3VASeDEvC)dUXAfi}o!SKS+WH=w_s?T6Jm@kJI8+T66N8+a5b?s@Spb@3oyj5{ z;^c9tck+vS8j32)xlgS1_ZejUDELwFc<%lm&$n;gXL}=O+nzmp4jpo`5ag1bab;z= zpXt5Z9vq$3DtQkMGgriTE?Zgc&f-`bkJ zJ^y}OSeRMyGoQQhQx<7VQgM{3kqYkju4d^}lYIN!VNr!^pu&BP6&{12=ga>4lx`WUTUcl~tL*&x@akRX=U80~`2GIy*Q@cH1iuW~+T)Aw$Vj)M9(JJ-hc~;9ZZ+)2F9=&<(o6a(YsNzTR_2w(H z{#Z7Dx$^Sz`adtvw@mPxo_$$5|ASj{T9uXJl9#6sZ;UiQ6aC@DPyK6Q@;^TJ+1{?Z zU$<)JJsk~=7cX9D=;`s*2Ictd&A+7%=_rV;?7y1yJ8M~`mG${8TZ1Im=H|p~Th}2V zlx)^7o2noA^S{w0w?q9Y=T6iW-dNF7sU3cQ>!Xdi=f(EzeHmG`f5{RRJw3gW*;i7` zRdaoed<<5c)RGSFxAW(40%fkO1uIv1o!_)jDOjP)_{S@GIj!jY`BQv3GXFkVEO&cp z`YC1KecLM?BmUgTUpK>`@UJuXIScEDX^xJLX=!O1zn7RSyZ88`!=}LX!p0#%EROB! zvLB+J9}4t|mu+V2+x=(#Db`yWa~7(q#-7@-YB}5WyEd;+hJQbLi|vxNcKEs}sg_f2 zInA@)OH9}IvagT%KRmN``ZKqbOTGg1|sjsE=>+H60`QLXxpY2K4@P6wqfAtt& zt{J~lOUFC$<3;@yje`DV41KQ8x5`h4T)JIqetuW+&7a0AE?v5`!1i;Zbcp4;lD*eh^EQ|S$}KB*66oSH zI`y;Jv?*+D)X~B_>+8O*_V73B+0f^h)B4L{%9cHQ?z}8H^p$<=>9~tW7*tx9?VYK6OLjb%xaf!CN$85i<{5%3mb`Yp zez9k<`aA23e+$ib6fA5|>JYb*F+4ldxLx4VjT=8c9+&5rHp{uR#It3>$H&Koo&4t6 z{Ji9?Z~OO)tM3Xy&7kkg=2g8Cxsvos*t-1PlIzA|f4Wqb@5+mQq4eaOYm? z>e_nx>8oru;cLs@rgw`R?f>&nJ@@@86#mrr|oUc}7&ie5!Z?4^z^+-24|A;(Vioc?RK)IUISs!FHa z+=ahwn>MtByM?cf`r0i2N8wU2kA8{ujCmQCm#8#GEWUd6>X)i3qPAAXwZ$*wcbnPU zKU>AQUBAxYK;uTxh>A>@-a#o>NmqgR4@=_Y6_(xm+bKOoWX(l~q*wm)Y&_Su^LT%~ z?KW-ceY-#2%?CeRFxHpuImZ3%l`)8EwzWe2tjPUF2XU+fra*w?lZlk{@uEI>^O zUElo?Pk!reGykSp>*OK4;ErbXnieTY$1~B(xRWn%)#Qw6KO8P8MCyoDy?tr-czds# z$p+8p*-|%uZ&KN2W?Hs;PTl^a-;UWWT|e3D-jtl3mzgdG)cU&jD%@v3q`i1``1&xB zr!OupZkcf2{{Nm08wy@rSa^E6e*c#>U)!ZJ{(ou6FdsDVGyj2wUR~WDjV=R0oV!Z6*%MVxv zMxRY9Nt=I3{eeECuH>P#ukMDf0u27IK-*aAp4{B;IpLn>fh#Iut4-C_+v{vTJeO^> z$#ea<%$7GxU%P7C{5f;xD6DD^T5I$5issWDOy@S#uIg!0xGx;w_SHSlV*WkN3C?eC zZce}a+V*yxzIV_H<_Sw|Z`Zxw{(s-4U0b(S#uh)`+ndm}NEXuI25slqwsRX}CG!HA z;0I5hJ-d}-wjYleZ4+*$$dVA9;D)>m+=BLk|v0dbx9p&mFydXeBOwdsvKEUlO zqtH?He4oB*6+W^3jq1*uqSjVcR(^SWd-lA)zu9*;%bmP$f8%VJ@X6DsxszP^H)O89 zF}JJxSDN6G`^`pDT5Ggbdsi+`{K{As6cI6F-aJ41b@dqsumAs}({Zro@A>oB?6)-3 z`S|+qc1w)C00OVc;aeyye&e^BeZs!KLzTE)EQr%#=FaoqUaIrV4vZ-vkP@?QQ; zUDCg`Tf~GFm#kUS^SrtI*aZ{bS6>3NMYI-IsMb48cyFn(cvqr<#1*$t>xGWfDqg9G zJh)T`THWON1Z2+iJ0DM7?q@4{q~d)^+u#1zlS$SQyt;aNd`suaGDKy{B)+-4P_n6J zJ*dK1H8nJORhHiRmpASS&M8i&4t}!DnyJkKX-v=T=aWQhGGhxozpJ>3(xFR{Z^*c%mW7I39_E)=3!m?z-R2CwS;p=As|_ZY`NPbEbCqx-~0TCceKOUjH`SB=XYb z%coDBa*99A{GiStog*?Y3(R_uFNyX#QExhXY?%nmP)y4G&yxb*&E!C~zZ2j}xL*1@LBx&)H`ZM1y& zmSyq9471q}uh<pRQ}&Y_oT* z*W1YPsg@x%gxw)8CGy{?Poj!P3=U2Bk*Re4bK2&cNgG+>0+xu!=!K`Irk0j|JvmwZ zZr=8zNuFL_r@%AFm%?ptdS=eLR=QyIYlrI-j<+}TNS$k(y#(C)V2qcP{qr$l-g8~C z?xRVDGkq@3xX7IH<-`l+Mb0u`rw3lk(Vlv7#cb}TmZ>XlO27SIATxcB=FQ3rnZI^w zUP`{mD|OT*_*e48D#*ONL*%39$B+L}I`;VEid9m*Vk^XFE%PiDx^X>Xi5z4V&kN2T z1rCM97iVkV)4mftEmcW)m#xξ5oqLG$`A_9_05Zk(PP|Jd=jbcma%tD;e3l+TWJ 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 P0|SGntDnm{r-UW|Uh!wq literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-to-desync-subsurf-2.png b/doc/book/src/images/content-updates/sync-to-desync-subsurf-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb6210c6594e2979d7177df8865866b098eddfe GIT binary patch literal 18069 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 b{rCNsD%r!pz`)??>gTe~DWM4fMP1|1 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-to-desync-subsurf-3.png b/doc/book/src/images/content-updates/sync-to-desync-subsurf-3.png new file mode 100644 index 0000000000000000000000000000000000000000..34bf7475ecf227af341f314e02e4a670861ce849 GIT binary patch literal 19371 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-to-desync-transition-1.png b/doc/book/src/images/content-updates/sync-to-desync-transition-1.png new file mode 100644 index 0000000000000000000000000000000000000000..cd69f3c34da5cf101bd2d0703225b7e695e1c03b GIT binary patch literal 9299 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 E0Lwg-GXMYp literal 0 HcmV?d00001 diff --git a/doc/book/src/images/content-updates/sync-to-desync-transition-2.png b/doc/book/src/images/content-updates/sync-to-desync-transition-2.png new file mode 100644 index 0000000000000000000000000000000000000000..677a0cdb1b182a19442633be3597337c6c869de9 GIT binary patch literal 15177 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 A_5c6? literal 0 HcmV?d00001 diff --git a/doc/book/src/images/icon.svg b/doc/book/src/images/icon.svg new file mode 100644 index 00000000..b2f16d0f --- /dev/null +++ b/doc/book/src/images/icon.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/doc/book/src/images/wayland-architecture.png b/doc/book/src/images/wayland-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..2be7da007d541a121cca973e7a95cec23ead2179 GIT binary patch literal 26968 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/wayland.png b/doc/book/src/images/wayland.png new file mode 100644 index 0000000000000000000000000000000000000000..c9937928ce9584a660ee10f7092eed2033f6eab8 GIT binary patch literal 5649 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 A`~Uy| literal 0 HcmV?d00001 diff --git a/doc/book/src/images/x-architecture.png b/doc/book/src/images/x-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..549e262d84ec3b6c1c3feac6d10dc62fb021a887 GIT binary patch literal 28785 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 literal 0 HcmV?d00001 diff --git a/doc/book/src/images/xwayland-architecture.png b/doc/book/src/images/xwayland-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..f24dc1837f2e190c9d38719420a844aeb5997efa GIT binary patch literal 7611 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 literal 0 HcmV?d00001 From cb4e8ada944813390aa56646a1d1ee0f7f5ae4c6 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 31 Jan 2026 11:09:33 +0100 Subject: [PATCH 1124/1152] doc: rewrite the book foreword Signed-off-by: Julian Orth --- doc/book/src/Foreword.md | 60 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/doc/book/src/Foreword.md b/doc/book/src/Foreword.md index 468b1654..f1b06625 100644 --- a/doc/book/src/Foreword.md +++ b/doc/book/src/Foreword.md @@ -1,15 +1,67 @@ + + # Preface -This document describes the (i) Wayland architecture, (ii) Wayland model of -operation and (iii) its library API. Also, the Wayland protocol specification is -shown in the Appendix. This document is aimed primarily at Wayland developers -and those looking to program with it; it does not cover application development. +This document describes the Wayland architecture and Wayland model of operation. +This document is aimed primarily at Wayland developers and those looking to +program with it; it does not cover application development. There have been many contributors to this document and since this is only the first edition many errors are expected to be found. We appreciate corrections. Yours, the Wayland open-source community November 2012 +## Protocol Documentation + +This document does not describe the semantics of individual messages sent +between compositors and clients. Consult the following documents to learn about +concrete Wayland interfaces, requests, and events. + +- [wayland.xml] - The official documentation of the core protocol. +- [wayland-protocols] - Standardized Wayland extension protocols. +- [wayland.app] - A community-maintained website that renders these protocols, + and many more, as easily accessible HTML pages. + +[wayland.xml]: https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/protocol/wayland.xml +[wayland-protocols]: https://gitlab.freedesktop.org/wayland/wayland-protocols +[wayland.app]: https://wayland.app + +## About the Book + +This book is written in markdown and converted to HTML using +[mdbook](https://rust-lang.github.io/mdBook). + +It supports the [CommonMark](https://commonmark.org/) dialect of markdown plus a number of +widely supported extensions: + +- `~~strikethrough~~` +- ```markdown + footnotes[^note] + + [^note]: text + ``` +- ```markdown + | Tables | Header2 | + |--------|---------| + | abc | def | + ``` +- ```markdown + - [x] Task lists + - [ ] Incomplete task + ``` +- ```markdown + definition lists + : This is the definition of a + definition list + ``` +- ```markdown + > [!NOTE] + > Admonitions + ``` + +The full list of extensions is documented +[here](https://rust-lang.github.io/mdBook/format/markdown.html#extensions). + ## Copyright Copyright © 2012 Kristian Høgsberg From 4f6ea74a0f84f6948c95e3ff72c29fc698af3524 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 31 Jan 2026 11:41:32 +0100 Subject: [PATCH 1125/1152] doc: add meson.build for book Signed-off-by: Julian Orth --- .gitlab-ci.yml | 4 +-- doc/book/meson.build | 58 ++++++++++++++++++++++++++++++++++++++++++++ doc/meson.build | 2 ++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 doc/book/meson.build diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9816859a..17298274 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -78,10 +78,10 @@ workflow: variables: BUILD_OS: debian FDO_DISTRIBUTION_VERSION: trixie - FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl meson ninja-build' + FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl mdbook meson ninja-build' # bump this tag every time you change something which requires rebuilding the # base image - FDO_DISTRIBUTION_TAG: "2025-12-27.0" + FDO_DISTRIBUTION_TAG: "2026-01-31.0" .debian-x86_64: extends: diff --git a/doc/book/meson.build b/doc/book/meson.build new file mode 100644 index 00000000..fa8f1dbb --- /dev/null +++ b/doc/book/meson.build @@ -0,0 +1,58 @@ +srcs = files( + 'src/Protocol.md', + 'src/Foreword.md', + 'src/Xwayland.md', + 'src/SUMMARY.md', + 'src/Content_Updates.md', + 'src/Color.md', + 'src/Message_XML.md', + 'src/Architecture.md', + 'src/Introduction.md', + 'src/images/content-updates/sync-to-desync-subsurf-3.png', + 'src/images/content-updates/sync-subsurf-case2-2.png', + 'src/images/content-updates/simple-synchronized-state-4.png', + 'src/images/content-updates/sync-subsurf-case2-3.png', + 'src/images/content-updates/sync-to-desync-transition-2.png', + 'src/images/content-updates/simple-desynchronized-state-4.png', + 'src/images/content-updates/simple-synchronized-state-3.png', + 'src/images/content-updates/simple-synchronized-state-1.png', + 'src/images/content-updates/sync-subsurf-case1-4.png', + 'src/images/content-updates/sync-to-desync-subsurf-1.png', + 'src/images/content-updates/simple-desynchronized-state-1.png', + 'src/images/content-updates/simple-desynchronized-state-3.png', + 'src/images/content-updates/simple-desynchronized-state-6.png', + 'src/images/content-updates/sync-subsurf-case1-2.png', + 'src/images/content-updates/sync-subsurf-case1-1.png', + 'src/images/content-updates/simple-synchronized-state-5.png', + 'src/images/content-updates/simple-synchronized-state-2.png', + 'src/images/content-updates/simple-desynchronized-state-2.png', + 'src/images/content-updates/content-update-legend.png', + 'src/images/content-updates/sync-to-desync-subsurf-2.png', + 'src/images/content-updates/sync-to-desync-transition-3.png', + 'src/images/content-updates/sync-subsurf-case2-1.png', + 'src/images/content-updates/sync-subsurf-case1-5.png', + 'src/images/content-updates/sync-subsurf-case1-3.png', + 'src/images/content-updates/simple-desynchronized-state-5.png', + 'src/images/content-updates/sync-to-desync-transition-1.png', + 'src/images/icon.svg', + 'src/images/x-architecture.png', + 'src/images/wayland.png', + 'src/images/wayland-architecture.png', + 'src/images/xwayland-architecture.png', + 'src/Compositors.md', +) + +custom_target( + 'Wayland-book', + command: [ + mdbook, + 'build', + '-d', meson.current_build_dir() / 'book', + meson.current_source_dir(), + ], + depend_files: srcs, + output: 'book', + build_by_default: true, + install: true, + install_dir: publican_install_prefix, +) diff --git a/doc/meson.build b/doc/meson.build index 44fda2ab..b9f6fcba 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -6,6 +6,7 @@ dot = find_program('dot') doxygen = find_program('doxygen') xsltproc = find_program('xsltproc') xmlto = find_program('xmlto') +mdbook = find_program('mdbook') cmd = run_command(doxygen, '--version', check: true) message('doxygen: ' + cmd.stdout().strip()) @@ -39,3 +40,4 @@ publican_html_dir = 'html' subdir('doxygen') subdir('publican') +subdir('book') From 1915dd17f0d98bd29ccb3f2e9f3938d044afcf95 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 2 Feb 2026 11:38:43 +0100 Subject: [PATCH 1126/1152] doc: link to website in doxygen Signed-off-by: Julian Orth --- doc/doxygen/mainpage.dox | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox index 352f69be..44332cd8 100644 --- a/doc/doxygen/mainpage.dox +++ b/doc/doxygen/mainpage.dox @@ -9,8 +9,8 @@ * - Cursor helper library API * * Further documentation about the architecture and principles of Wayland is - * available in the - * Wayland Book + * available on the + * website. * * @section ifaces Interfaces * For the list of available interfaces, please see the From ddd4f652404be8c59da7cc01f676d13b0390f3bf Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 31 Jan 2026 11:59:10 +0100 Subject: [PATCH 1127/1152] doc: remove most content from docbook Signed-off-by: Julian Orth --- doc/publican/Architecture.xml | 392 ----- doc/publican/Color.xml | 139 -- doc/publican/Compositors.xml | 128 -- doc/publican/Content_Updates.xml | 460 ----- doc/publican/Introduction.xml | 116 -- doc/publican/Message_XML.xml | 928 ---------- doc/publican/Protocol.xml | 592 ------- doc/publican/Wayland.xml | 8 - doc/publican/Xwayland.xml | 168 -- .../content-updates/content-update-legend.png | Bin 15946 -> 0 bytes .../content-updates/content-updates.drawio | 1528 ----------------- .../html/images/content-updates/meson.build | 35 - .../simple-desynchronized-state-1.png | Bin 2037 -> 0 bytes .../simple-desynchronized-state-2.png | Bin 6732 -> 0 bytes .../simple-desynchronized-state-3.png | Bin 1625 -> 0 bytes .../simple-desynchronized-state-4.png | Bin 7302 -> 0 bytes .../simple-desynchronized-state-5.png | Bin 12728 -> 0 bytes .../simple-desynchronized-state-6.png | Bin 2102 -> 0 bytes .../simple-desynchronized.drawio | 198 --- .../simple-synchronized-state-1.png | Bin 2117 -> 0 bytes .../simple-synchronized-state-2.png | Bin 2586 -> 0 bytes .../simple-synchronized-state-3.png | Bin 2989 -> 0 bytes .../simple-synchronized-state-4.png | Bin 17710 -> 0 bytes .../simple-synchronized-state-5.png | Bin 2209 -> 0 bytes .../simple-synchronized.drawio | 207 --- .../content-updates/sync-subsurf-case1-1.png | Bin 26995 -> 0 bytes .../content-updates/sync-subsurf-case1-2.png | Bin 27535 -> 0 bytes .../content-updates/sync-subsurf-case1-3.png | Bin 22771 -> 0 bytes .../content-updates/sync-subsurf-case1-4.png | Bin 22017 -> 0 bytes .../content-updates/sync-subsurf-case1-5.png | Bin 10932 -> 0 bytes .../content-updates/sync-subsurf-case1.drawio | 500 ------ .../content-updates/sync-subsurf-case2-1.png | Bin 26210 -> 0 bytes .../content-updates/sync-subsurf-case2-2.png | Bin 25821 -> 0 bytes .../content-updates/sync-subsurf-case2-3.png | Bin 10069 -> 0 bytes .../content-updates/sync-subsurf-case2.drawio | 287 ---- .../sync-to-desync-subsurf-1.png | Bin 18621 -> 0 bytes .../sync-to-desync-subsurf-2.png | Bin 18069 -> 0 bytes .../sync-to-desync-subsurf-3.png | Bin 19371 -> 0 bytes .../sync-to-desync-subsurf.drawio | 223 --- .../sync-to-desync-transition-1.png | Bin 9299 -> 0 bytes .../sync-to-desync-transition-2.png | Bin 15177 -> 0 bytes .../sync-to-desync-transition-3.png | Bin 15872 -> 0 bytes .../sync-to-desync-transition.drawio | 203 --- doc/publican/html/images/icon.svg | 19 - doc/publican/html/images/meson.build | 37 - .../html/images/wayland-architecture.gv | 36 - doc/publican/html/images/x-architecture.gv | 53 - .../html/images/xwayland-architecture.png | Bin 7611 -> 0 bytes doc/publican/meson.build | 27 - 49 files changed, 6284 deletions(-) delete mode 100644 doc/publican/Architecture.xml delete mode 100644 doc/publican/Color.xml delete mode 100644 doc/publican/Compositors.xml delete mode 100644 doc/publican/Content_Updates.xml delete mode 100644 doc/publican/Introduction.xml delete mode 100644 doc/publican/Message_XML.xml delete mode 100644 doc/publican/Protocol.xml delete mode 100644 doc/publican/Xwayland.xml delete mode 100644 doc/publican/html/images/content-updates/content-update-legend.png delete mode 100644 doc/publican/html/images/content-updates/content-updates.drawio delete mode 100644 doc/publican/html/images/content-updates/meson.build delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-1.png delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-2.png delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-3.png delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-4.png delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-5.png delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized-state-6.png delete mode 100644 doc/publican/html/images/content-updates/simple-desynchronized.drawio delete mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-1.png delete mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-2.png delete mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-3.png delete mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-4.png delete mode 100644 doc/publican/html/images/content-updates/simple-synchronized-state-5.png delete mode 100644 doc/publican/html/images/content-updates/simple-synchronized.drawio delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-1.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-2.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-3.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-4.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1-5.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case1.drawio delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2-1.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2-2.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2-3.png delete mode 100644 doc/publican/html/images/content-updates/sync-subsurf-case2.drawio delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf-1.png delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf-2.png delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf-3.png delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-subsurf.drawio delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition-1.png delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition-2.png delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition-3.png delete mode 100644 doc/publican/html/images/content-updates/sync-to-desync-transition.drawio delete mode 100644 doc/publican/html/images/icon.svg delete mode 100644 doc/publican/html/images/meson.build delete mode 100644 doc/publican/html/images/wayland-architecture.gv delete mode 100644 doc/publican/html/images/x-architecture.gv delete mode 100644 doc/publican/html/images/xwayland-architecture.png diff --git a/doc/publican/Architecture.xml b/doc/publican/Architecture.xml deleted file mode 100644 index fb317685..00000000 --- a/doc/publican/Architecture.xml +++ /dev/null @@ -1,392 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - Wayland Architecture -