commit
						6d53770d65
					
				@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					.PHONY: all clean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CC = gcc
 | 
				
			||||||
 | 
					CLIBS = -lwayland-client
 | 
				
			||||||
 | 
					CFLAGS = $(CLIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXT_SOURCE_PROTOCOL_IMPL = ext-image-capture-source-v1-protocol.c 
 | 
				
			||||||
 | 
					EXT_SOURCE_PROTOCOL_HEADER = ext-image-capture-source-v1-protocol.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXT_CAPTURE_PROTOCOL_IMPL = ext-image-copy-capture-v1-protocol.c 
 | 
				
			||||||
 | 
					EXT_CAPTURE_PROTOCOL_HEADER = ext-image-copy-capture-v1-protocol.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXT_TOPLEVEL_PROTOCOL_IMPL = ext-foreign-toplevel-list-v1-protocol.c 
 | 
				
			||||||
 | 
					EXT_TOPLEVEL_PROTOCOL_HEADER = ext-foreign-toplevel-list-v1-protocol.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SRC = main.c
 | 
				
			||||||
 | 
					OUT = screencap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROTOCOL_IMPLS = $(EXT_TOPLEVEL_PROTOCOL_IMPL) $(EXT_SOURCE_PROTOCOL_IMPL) $(EXT_CAPTURE_PROTOCOL_IMPL)
 | 
				
			||||||
 | 
					PROTOCOL_HEADERS = $(EXT_TOPLEVEL_PROTOCOL_HEADER) $(EXT_SOURCE_PROTOCOL_HEADER) $(EXT_CAPTURE_PROTOCOL_HEADER)
 | 
				
			||||||
 | 
					PROTOCOLS = $(PROTOCOL_IMPLS) $(PROTOCOL_HEADERS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: $(OUT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -f $(OUT)
 | 
				
			||||||
 | 
						rm -f $(PROTOCOLS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT): $(PROTOCOLS) $(SRC)
 | 
				
			||||||
 | 
						$(CC) $(PROTOCOL_IMPLS) $(SRC) $(CFLAGS) -o $(OUT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(EXT_SOURCE_PROTOCOL_IMPL):
 | 
				
			||||||
 | 
						wayland-scanner private-code ./ext-image-capture-source-v1.xml $(EXT_SOURCE_PROTOCOL_IMPL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(EXT_SOURCE_PROTOCOL_HEADER):
 | 
				
			||||||
 | 
						wayland-scanner client-header ./ext-image-capture-source-v1.xml $(EXT_SOURCE_PROTOCOL_HEADER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(EXT_CAPTURE_PROTOCOL_IMPL):
 | 
				
			||||||
 | 
						wayland-scanner private-code ./ext-image-copy-capture-v1.xml $(EXT_CAPTURE_PROTOCOL_IMPL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(EXT_CAPTURE_PROTOCOL_HEADER):
 | 
				
			||||||
 | 
						wayland-scanner client-header ./ext-image-copy-capture-v1.xml $(EXT_CAPTURE_PROTOCOL_HEADER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(EXT_TOPLEVEL_PROTOCOL_IMPL):
 | 
				
			||||||
 | 
						wayland-scanner private-code ./ext-foreign-toplevel-list-v1.xml $(EXT_TOPLEVEL_PROTOCOL_IMPL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(EXT_TOPLEVEL_PROTOCOL_HEADER):
 | 
				
			||||||
 | 
						wayland-scanner client-header ./ext-foreign-toplevel-list-v1.xml $(EXT_TOPLEVEL_PROTOCOL_HEADER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					A simple Wayland screenshotting utility that utilizes the new `ext-image-capture-source-v1` & `ext-image-copy-capture-v1`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Runtime Dependencies: 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `libwayland-client`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Make Dependencies:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `wayland-scanner`
 | 
				
			||||||
 | 
					- `make`
 | 
				
			||||||
 | 
					- `gcc`
 | 
				
			||||||
@ -0,0 +1,219 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<protocol name="ext_foreign_toplevel_list_v1">
 | 
				
			||||||
 | 
					  <copyright>
 | 
				
			||||||
 | 
					    Copyright © 2018 Ilia Bozhinov
 | 
				
			||||||
 | 
					    Copyright © 2020 Isaac Freund
 | 
				
			||||||
 | 
					    Copyright © 2022 wb9688
 | 
				
			||||||
 | 
					    Copyright © 2023 i509VCB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					  </copyright>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <description summary="list toplevels">
 | 
				
			||||||
 | 
					    The purpose of this protocol is to provide protocol object handles for
 | 
				
			||||||
 | 
					    toplevels, possibly originating from another client.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This protocol is intentionally minimalistic and expects additional
 | 
				
			||||||
 | 
					    functionality (e.g. creating a screencopy source from a toplevel handle,
 | 
				
			||||||
 | 
					    getting information about the state of the toplevel) to be implemented
 | 
				
			||||||
 | 
					    in extension protocols.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The compositor may choose to restrict this protocol to a special client
 | 
				
			||||||
 | 
					    launched by the compositor itself or expose it to all clients,
 | 
				
			||||||
 | 
					    this is compositor policy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The key words "must", "must not", "required", "shall", "shall not",
 | 
				
			||||||
 | 
					    "should", "should not", "recommended",  "may", and "optional" in this
 | 
				
			||||||
 | 
					    document are to be interpreted as described in IETF RFC 2119.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Warning! The protocol described in this file is currently in the testing
 | 
				
			||||||
 | 
					    phase. Backward compatible changes may be added together with the
 | 
				
			||||||
 | 
					    corresponding interface version bump. Backward incompatible changes can
 | 
				
			||||||
 | 
					    only be done by creating a new major version of the extension.
 | 
				
			||||||
 | 
					  </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_foreign_toplevel_list_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="list toplevels">
 | 
				
			||||||
 | 
					      A toplevel is defined as a surface with a role similar to xdg_toplevel.
 | 
				
			||||||
 | 
					      XWayland surfaces may be treated like toplevels in this protocol.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      After a client binds the ext_foreign_toplevel_list_v1, each mapped
 | 
				
			||||||
 | 
					      toplevel window will be sent using the ext_foreign_toplevel_list_v1.toplevel
 | 
				
			||||||
 | 
					      event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Clients which only care about the current state can perform a roundtrip after
 | 
				
			||||||
 | 
					      binding this global.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      For each instance of ext_foreign_toplevel_list_v1, the compositor must
 | 
				
			||||||
 | 
					      create a new ext_foreign_toplevel_handle_v1 object for each mapped toplevel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      If a compositor implementation sends the ext_foreign_toplevel_list_v1.finished
 | 
				
			||||||
 | 
					      event after the global is bound, the compositor must not send any
 | 
				
			||||||
 | 
					      ext_foreign_toplevel_list_v1.toplevel events.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="toplevel">
 | 
				
			||||||
 | 
					      <description summary="a toplevel has been created">
 | 
				
			||||||
 | 
					        This event is emitted whenever a new toplevel window is created. It is
 | 
				
			||||||
 | 
					        emitted for all toplevels, regardless of the app that has created them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        All initial properties of the toplevel (identifier, title, app_id) will be sent
 | 
				
			||||||
 | 
					        immediately after this event using the corresponding events for
 | 
				
			||||||
 | 
					        ext_foreign_toplevel_handle_v1. The compositor will use the
 | 
				
			||||||
 | 
					        ext_foreign_toplevel_handle_v1.done event to indicate when all data has
 | 
				
			||||||
 | 
					        been sent.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="toplevel" type="new_id" interface="ext_foreign_toplevel_handle_v1"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="finished">
 | 
				
			||||||
 | 
					      <description summary="the compositor has finished with the toplevel manager">
 | 
				
			||||||
 | 
					        This event indicates that the compositor is done sending events
 | 
				
			||||||
 | 
					        to this object. The client should destroy the object.
 | 
				
			||||||
 | 
					        See ext_foreign_toplevel_list_v1.destroy for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The compositor must not send any more toplevel events after this event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="stop">
 | 
				
			||||||
 | 
					      <description summary="stop sending events">
 | 
				
			||||||
 | 
					        This request indicates that the client no longer wishes to receive
 | 
				
			||||||
 | 
					        events for new toplevels.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The Wayland protocol is asynchronous, meaning the compositor may send
 | 
				
			||||||
 | 
					        further toplevel events until the stop request is processed.
 | 
				
			||||||
 | 
					        The client should wait for a ext_foreign_toplevel_list_v1.finished
 | 
				
			||||||
 | 
					        event before destroying this object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy the ext_foreign_toplevel_list_v1 object">
 | 
				
			||||||
 | 
					        This request should be called either when the client will no longer
 | 
				
			||||||
 | 
					        use the ext_foreign_toplevel_list_v1 or after the finished event
 | 
				
			||||||
 | 
					        has been received to allow destruction of the object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If a client wishes to destroy this object it should send a
 | 
				
			||||||
 | 
					        ext_foreign_toplevel_list_v1.stop request and wait for a ext_foreign_toplevel_list_v1.finished
 | 
				
			||||||
 | 
					        event, then destroy the handles and then this object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_foreign_toplevel_handle_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="a mapped toplevel">
 | 
				
			||||||
 | 
					      A ext_foreign_toplevel_handle_v1 object represents a mapped toplevel
 | 
				
			||||||
 | 
					      window. A single app may have multiple mapped toplevels.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy the ext_foreign_toplevel_handle_v1 object">
 | 
				
			||||||
 | 
					        This request should be used when the client will no longer use the handle
 | 
				
			||||||
 | 
					        or after the closed event has been received to allow destruction of the
 | 
				
			||||||
 | 
					        object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        When a handle is destroyed, a new handle may not be created by the server
 | 
				
			||||||
 | 
					        until the toplevel is unmapped and then remapped. Destroying a toplevel handle
 | 
				
			||||||
 | 
					        is not recommended unless the client is cleaning up child objects
 | 
				
			||||||
 | 
					        before destroying the ext_foreign_toplevel_list_v1 object, the toplevel
 | 
				
			||||||
 | 
					        was closed or the toplevel handle will not be used in the future.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Other protocols which extend the ext_foreign_toplevel_handle_v1
 | 
				
			||||||
 | 
					        interface should require destructors for extension interfaces be
 | 
				
			||||||
 | 
					        called before allowing the toplevel handle to be destroyed.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="closed">
 | 
				
			||||||
 | 
					      <description summary="the toplevel has been closed">
 | 
				
			||||||
 | 
					        The server will emit no further events on the ext_foreign_toplevel_handle_v1
 | 
				
			||||||
 | 
					        after this event. Any requests received aside from the destroy request must
 | 
				
			||||||
 | 
					        be ignored. Upon receiving this event, the client should destroy the handle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Other protocols which extend the ext_foreign_toplevel_handle_v1
 | 
				
			||||||
 | 
					        interface must also ignore requests other than destructors.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="done">
 | 
				
			||||||
 | 
					      <description summary="all information about the toplevel has been sent">
 | 
				
			||||||
 | 
					        This event is sent after all changes in the toplevel state have
 | 
				
			||||||
 | 
					        been sent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This allows changes to the ext_foreign_toplevel_handle_v1 properties
 | 
				
			||||||
 | 
					        to be atomically applied. Other protocols which extend the
 | 
				
			||||||
 | 
					        ext_foreign_toplevel_handle_v1 interface may use this event to also
 | 
				
			||||||
 | 
					        atomically apply any pending state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This event must not be sent after the ext_foreign_toplevel_handle_v1.closed
 | 
				
			||||||
 | 
					        event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="title">
 | 
				
			||||||
 | 
					      <description summary="title change">
 | 
				
			||||||
 | 
					        The title of the toplevel has changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The configured state must not be applied immediately. See
 | 
				
			||||||
 | 
					        ext_foreign_toplevel_handle_v1.done for details.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="title" type="string"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="app_id">
 | 
				
			||||||
 | 
					      <description summary="app_id change">
 | 
				
			||||||
 | 
					        The app id of the toplevel has changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The configured state must not be applied immediately. See
 | 
				
			||||||
 | 
					        ext_foreign_toplevel_handle_v1.done for details.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="app_id" type="string"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="identifier">
 | 
				
			||||||
 | 
					      <description summary="a stable identifier for a toplevel">
 | 
				
			||||||
 | 
					        This identifier is used to check if two or more toplevel handles belong
 | 
				
			||||||
 | 
					        to the same toplevel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The identifier is useful for command line tools or privileged clients
 | 
				
			||||||
 | 
					        which may need to reference an exact toplevel across processes or
 | 
				
			||||||
 | 
					        instances of the ext_foreign_toplevel_list_v1 global.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The compositor must only send this event when the handle is created.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The identifier must be unique per toplevel and it's handles. Two different
 | 
				
			||||||
 | 
					        toplevels must not have the same identifier. The identifier is only valid
 | 
				
			||||||
 | 
					        as long as the toplevel is mapped. If the toplevel is unmapped the identifier
 | 
				
			||||||
 | 
					        must not be reused. An identifier must not be reused by the compositor to
 | 
				
			||||||
 | 
					        ensure there are no races when sharing identifiers between processes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        An identifier is a string that contains up to 32 printable ASCII bytes.
 | 
				
			||||||
 | 
					        An identifier must not be an empty string. It is recommended that a
 | 
				
			||||||
 | 
					        compositor includes an opaque generation value in identifiers. How the
 | 
				
			||||||
 | 
					        generation value is used when generating the identifier is implementation
 | 
				
			||||||
 | 
					        dependent.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="identifier" type="string"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					</protocol>
 | 
				
			||||||
@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<protocol name="ext_image_capture_source_v1">
 | 
				
			||||||
 | 
					  <copyright>
 | 
				
			||||||
 | 
					    Copyright © 2022 Andri Yngvason
 | 
				
			||||||
 | 
					    Copyright © 2024 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 (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.
 | 
				
			||||||
 | 
					  </copyright>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <description summary="opaque image capture source objects">
 | 
				
			||||||
 | 
					    This protocol serves as an intermediary between capturing protocols and
 | 
				
			||||||
 | 
					    potential image capture sources such as outputs and toplevels.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This protocol may be extended to support more image capture sources in the
 | 
				
			||||||
 | 
					    future, thereby adding those image capture sources to other protocols that
 | 
				
			||||||
 | 
					    use the image capture source object without having to modify those
 | 
				
			||||||
 | 
					    protocols.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Warning! The protocol described in this file is currently in the testing
 | 
				
			||||||
 | 
					    phase. Backward compatible changes may be added together with the
 | 
				
			||||||
 | 
					    corresponding interface version bump. Backward incompatible changes can
 | 
				
			||||||
 | 
					    only be done by creating a new major version of the extension.
 | 
				
			||||||
 | 
					  </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_image_capture_source_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="opaque image capture source object">
 | 
				
			||||||
 | 
					      The image capture source object is an opaque descriptor for a capturable
 | 
				
			||||||
 | 
					      resource.  This resource may be any sort of entity from which an image
 | 
				
			||||||
 | 
					      may be derived.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Note, because ext_image_capture_source_v1 objects are created from multiple
 | 
				
			||||||
 | 
					      independent factory interfaces, the ext_image_capture_source_v1 interface is
 | 
				
			||||||
 | 
					      frozen at version 1.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="delete this object">
 | 
				
			||||||
 | 
					        Destroys the image capture source. This request may be sent at any time
 | 
				
			||||||
 | 
					        by the client.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_output_image_capture_source_manager_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="image capture source manager for outputs">
 | 
				
			||||||
 | 
					      A manager for creating image capture source objects for wl_output objects.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="create_source">
 | 
				
			||||||
 | 
					      <description summary="create source object for output">
 | 
				
			||||||
 | 
					        Creates a source object for an output. Images captured from this source
 | 
				
			||||||
 | 
					        will show the same content as the output. Some elements may be omitted,
 | 
				
			||||||
 | 
					        such as cursors and overlays that have been marked as transparent to
 | 
				
			||||||
 | 
					        capturing.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="source" type="new_id" interface="ext_image_capture_source_v1"/>
 | 
				
			||||||
 | 
					      <arg name="output" type="object" interface="wl_output"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="delete this object">
 | 
				
			||||||
 | 
					        Destroys the manager. This request may be sent at any time by the client
 | 
				
			||||||
 | 
					        and objects created by the manager will remain valid after its
 | 
				
			||||||
 | 
					        destruction.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_foreign_toplevel_image_capture_source_manager_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="image capture source manager for foreign toplevels">
 | 
				
			||||||
 | 
					      A manager for creating image capture source objects for
 | 
				
			||||||
 | 
					      ext_foreign_toplevel_handle_v1 objects.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="create_source">
 | 
				
			||||||
 | 
					      <description summary="create source object for foreign toplevel">
 | 
				
			||||||
 | 
					        Creates a source object for a foreign toplevel handle. Images captured
 | 
				
			||||||
 | 
					        from this source will show the same content as the toplevel.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="source" type="new_id" interface="ext_image_capture_source_v1"/>
 | 
				
			||||||
 | 
					      <arg name="toplevel_handle" type="object" interface="ext_foreign_toplevel_handle_v1"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="delete this object">
 | 
				
			||||||
 | 
					        Destroys the manager. This request may be sent at any time by the client
 | 
				
			||||||
 | 
					        and objects created by the manager will remain valid after its
 | 
				
			||||||
 | 
					        destruction.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					</protocol>
 | 
				
			||||||
@ -0,0 +1,456 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<protocol name="ext_image_copy_capture_v1">
 | 
				
			||||||
 | 
					  <copyright>
 | 
				
			||||||
 | 
					    Copyright © 2021-2023 Andri Yngvason
 | 
				
			||||||
 | 
					    Copyright © 2024 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 (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.
 | 
				
			||||||
 | 
					  </copyright>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <description summary="image capturing into client buffers">
 | 
				
			||||||
 | 
					    This protocol allows clients to ask the compositor to capture image sources
 | 
				
			||||||
 | 
					    such as outputs and toplevels into user submitted buffers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Warning! The protocol described in this file is currently in the testing
 | 
				
			||||||
 | 
					    phase. Backward compatible changes may be added together with the
 | 
				
			||||||
 | 
					    corresponding interface version bump. Backward incompatible changes can
 | 
				
			||||||
 | 
					    only be done by creating a new major version of the extension.
 | 
				
			||||||
 | 
					  </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_image_copy_capture_manager_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="manager to inform clients and begin capturing">
 | 
				
			||||||
 | 
					      This object is a manager which offers requests to start capturing from a
 | 
				
			||||||
 | 
					      source.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="invalid_option" value="1" summary="invalid option flag"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="options" bitfield="true">
 | 
				
			||||||
 | 
					      <entry name="paint_cursors" value="1" summary="paint cursors onto captured frames"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="create_session">
 | 
				
			||||||
 | 
					      <description summary="capture an image capture source">
 | 
				
			||||||
 | 
					        Create a capturing session for an image capture source.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the paint_cursors option is set, cursors shall be composited onto
 | 
				
			||||||
 | 
					        the captured frame. The cursor must not be composited onto the frame
 | 
				
			||||||
 | 
					        if this flag is not set.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the options bitfield is invalid, the invalid_option protocol error
 | 
				
			||||||
 | 
					        is sent.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="session" type="new_id" interface="ext_image_copy_capture_session_v1"/>
 | 
				
			||||||
 | 
					      <arg name="source" type="object" interface="ext_image_capture_source_v1"/>
 | 
				
			||||||
 | 
					      <arg name="options" type="uint" enum="options"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="create_pointer_cursor_session">
 | 
				
			||||||
 | 
					      <description summary="capture the pointer cursor of an image capture source">
 | 
				
			||||||
 | 
					        Create a cursor capturing session for the pointer of an image capture
 | 
				
			||||||
 | 
					        source.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="session" type="new_id" interface="ext_image_copy_capture_cursor_session_v1"/>
 | 
				
			||||||
 | 
					      <arg name="source" type="object" interface="ext_image_capture_source_v1"/>
 | 
				
			||||||
 | 
					      <arg name="pointer" type="object" interface="wl_pointer"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy the manager">
 | 
				
			||||||
 | 
					        Destroy the manager object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Other objects created via this interface are unaffected.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_image_copy_capture_session_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="image copy capture session">
 | 
				
			||||||
 | 
					      This object represents an active image copy capture session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      After a capture session is created, buffer constraint events will be
 | 
				
			||||||
 | 
					      emitted from the compositor to tell the client which buffer types and
 | 
				
			||||||
 | 
					      formats are supported for reading from the session. The compositor may
 | 
				
			||||||
 | 
					      re-send buffer constraint events whenever they change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      The advertise buffer constraints, the compositor must send in no
 | 
				
			||||||
 | 
					      particular order: zero or more shm_format and dmabuf_format events, zero
 | 
				
			||||||
 | 
					      or one dmabuf_device event, and exactly one buffer_size event. Then the
 | 
				
			||||||
 | 
					      compositor must send a done event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      When the client has received all the buffer constraints, it can create a
 | 
				
			||||||
 | 
					      buffer accordingly, attach it to the capture session using the
 | 
				
			||||||
 | 
					      attach_buffer request, set the buffer damage using the damage_buffer
 | 
				
			||||||
 | 
					      request and then send the capture request.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="duplicate_frame" value="1"
 | 
				
			||||||
 | 
					        summary="create_frame sent before destroying previous frame"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="buffer_size">
 | 
				
			||||||
 | 
					      <description summary="image capture source dimensions">
 | 
				
			||||||
 | 
					        Provides the dimensions of the source image in buffer pixel coordinates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The client must attach buffers that match this size.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="width" type="uint" summary="buffer width"/>
 | 
				
			||||||
 | 
					      <arg name="height" type="uint" summary="buffer height"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="shm_format">
 | 
				
			||||||
 | 
					      <description summary="shm buffer format">
 | 
				
			||||||
 | 
					        Provides the format that must be used for shared-memory buffers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This event may be emitted multiple times, in which case the client may
 | 
				
			||||||
 | 
					        choose any given format.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="format" type="uint" enum="wl_shm.format" summary="shm format"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="dmabuf_device">
 | 
				
			||||||
 | 
					      <description summary="dma-buf device">
 | 
				
			||||||
 | 
					        This event advertises the device buffers must be allocated on for
 | 
				
			||||||
 | 
					        dma-buf buffers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        In general the device is a DRM node. The DRM node type (primary vs.
 | 
				
			||||||
 | 
					        render) is unspecified. Clients must not rely on the compositor sending
 | 
				
			||||||
 | 
					        a particular node type. Clients cannot check two devices for equality
 | 
				
			||||||
 | 
					        by comparing the dev_t value.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="device" type="array" summary="device dev_t value"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="dmabuf_format">
 | 
				
			||||||
 | 
					      <description summary="dma-buf format">
 | 
				
			||||||
 | 
					        Provides the format that must be used for dma-buf buffers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The client may choose any of the modifiers advertised in the array of
 | 
				
			||||||
 | 
					        64-bit unsigned integers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This event may be emitted multiple times, in which case the client may
 | 
				
			||||||
 | 
					        choose any given format.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="format" type="uint" summary="drm format code"/>
 | 
				
			||||||
 | 
					      <arg name="modifiers" type="array" summary="drm format modifiers"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="done">
 | 
				
			||||||
 | 
					      <description summary="all constraints have been sent">
 | 
				
			||||||
 | 
					        This event is sent once when all buffer constraint events have been
 | 
				
			||||||
 | 
					        sent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The compositor must always end a batch of buffer constraint events with
 | 
				
			||||||
 | 
					        this event, regardless of whether it sends the initial constraints or
 | 
				
			||||||
 | 
					        an update.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="stopped">
 | 
				
			||||||
 | 
					      <description summary="session is no longer available">
 | 
				
			||||||
 | 
					        This event indicates that the capture session has stopped and is no
 | 
				
			||||||
 | 
					        longer available. This can happen in a number of cases, e.g. when the
 | 
				
			||||||
 | 
					        underlying source is destroyed, if the user decides to end the image
 | 
				
			||||||
 | 
					        capture, or if an unrecoverable runtime error has occurred.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The client should destroy the session after receiving this event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="create_frame">
 | 
				
			||||||
 | 
					      <description summary="create a frame">
 | 
				
			||||||
 | 
					        Create a capture frame for this session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        At most one frame object can exist for a given session at any time. If
 | 
				
			||||||
 | 
					        a client sends a create_frame request before a previous frame object
 | 
				
			||||||
 | 
					        has been destroyed, the duplicate_frame protocol error is raised.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="frame" type="new_id" interface="ext_image_copy_capture_frame_v1"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="delete this object">
 | 
				
			||||||
 | 
					        Destroys the session. This request can be sent at any time by the
 | 
				
			||||||
 | 
					        client.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request doesn't affect ext_image_copy_capture_frame_v1 objects created by
 | 
				
			||||||
 | 
					        this object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_image_copy_capture_frame_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="image capture frame">
 | 
				
			||||||
 | 
					      This object represents an image capture frame.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      The client should attach a buffer, damage the buffer, and then send a
 | 
				
			||||||
 | 
					      capture request.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      If the capture is successful, the compositor must send the frame metadata
 | 
				
			||||||
 | 
					      (transform, damage, presentation_time in any order) followed by the ready
 | 
				
			||||||
 | 
					      event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      If the capture fails, the compositor must send the failed event.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="no_buffer" value="1" summary="capture sent without attach_buffer"/>
 | 
				
			||||||
 | 
					      <entry name="invalid_buffer_damage" value="2" summary="invalid buffer damage"/>
 | 
				
			||||||
 | 
					      <entry name="already_captured" value="3" summary="capture request has been sent"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy this object">
 | 
				
			||||||
 | 
					        Destroys the session. This request can be sent at any time by the
 | 
				
			||||||
 | 
					        client.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="attach_buffer">
 | 
				
			||||||
 | 
					      <description summary="attach buffer to session">
 | 
				
			||||||
 | 
					        Attach a buffer to the session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The wl_buffer.release request is unused.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The new buffer replaces any previously attached buffer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request must not be sent after capture, or else the
 | 
				
			||||||
 | 
					        already_captured protocol error is raised.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="buffer" type="object" interface="wl_buffer"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="damage_buffer">
 | 
				
			||||||
 | 
					      <description summary="damage buffer">
 | 
				
			||||||
 | 
					        Apply damage to the buffer which is to be captured next. This request
 | 
				
			||||||
 | 
					        may be sent multiple times to describe a region.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The client indicates the accumulated damage since this wl_buffer was
 | 
				
			||||||
 | 
					        last captured. During capture, the compositor will update the buffer
 | 
				
			||||||
 | 
					        with at least the union of the region passed by the client and the
 | 
				
			||||||
 | 
					        region advertised by ext_image_copy_capture_frame_v1.damage.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        When a wl_buffer is captured for the first time, or when the client
 | 
				
			||||||
 | 
					        doesn't track damage, the client must damage the whole buffer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This is for optimisation purposes. The compositor may use this
 | 
				
			||||||
 | 
					        information to reduce copying.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        These coordinates originate from the upper left corner of the buffer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If x or y are strictly negative, or if width or height are negative or
 | 
				
			||||||
 | 
					        zero, the invalid_buffer_damage protocol error is raised.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request must not be sent after capture, or else the
 | 
				
			||||||
 | 
					        already_captured protocol error is raised.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="x" type="int" summary="region x coordinate"/>
 | 
				
			||||||
 | 
					      <arg name="y" type="int" summary="region y coordinate"/>
 | 
				
			||||||
 | 
					      <arg name="width" type="int" summary="region width"/>
 | 
				
			||||||
 | 
					      <arg name="height" type="int" summary="region height"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="capture">
 | 
				
			||||||
 | 
					      <description summary="capture a frame">
 | 
				
			||||||
 | 
					        Capture a frame.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Unless this is the first successful captured frame performed in this
 | 
				
			||||||
 | 
					        session, the compositor may wait an indefinite amount of time for the
 | 
				
			||||||
 | 
					        source content to change before performing the copy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request may only be sent once, or else the already_captured
 | 
				
			||||||
 | 
					        protocol error is raised. A buffer must be attached before this request
 | 
				
			||||||
 | 
					        is sent, or else the no_buffer protocol error is raised.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="transform">
 | 
				
			||||||
 | 
					      <description summary="buffer transform">
 | 
				
			||||||
 | 
					        This event is sent before the ready event and holds the transform that
 | 
				
			||||||
 | 
					        the compositor has applied to the buffer contents.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="transform" type="uint" enum="wl_output.transform"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="damage">
 | 
				
			||||||
 | 
					      <description summary="buffer damaged region">
 | 
				
			||||||
 | 
					        This event is sent before the ready event. It may be generated multiple
 | 
				
			||||||
 | 
					        times to describe a region.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The first captured frame in a session will always carry full damage.
 | 
				
			||||||
 | 
					        Subsequent frames' damaged regions describe which parts of the buffer
 | 
				
			||||||
 | 
					        have changed since the last ready event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        These coordinates originate in the upper left corner of the buffer.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="x" type="int" summary="damage x coordinate"/>
 | 
				
			||||||
 | 
					      <arg name="y" type="int" summary="damage y coordinate"/>
 | 
				
			||||||
 | 
					      <arg name="width" type="int" summary="damage width"/>
 | 
				
			||||||
 | 
					      <arg name="height" type="int" summary="damage height"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="presentation_time">
 | 
				
			||||||
 | 
					      <description summary="presentation time of the frame">
 | 
				
			||||||
 | 
					        This event indicates the time at which the frame is presented to the
 | 
				
			||||||
 | 
					        output in system monotonic time. This event is sent before the ready
 | 
				
			||||||
 | 
					        event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
 | 
				
			||||||
 | 
					        each component being an unsigned 32-bit value. Whole seconds are in
 | 
				
			||||||
 | 
					        tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo,
 | 
				
			||||||
 | 
					        and the additional fractional part in tv_nsec as nanoseconds. Hence,
 | 
				
			||||||
 | 
					        for valid timestamps tv_nsec must be in [0, 999999999].
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="tv_sec_hi" type="uint"
 | 
				
			||||||
 | 
					           summary="high 32 bits of the seconds part of the timestamp"/>
 | 
				
			||||||
 | 
					      <arg name="tv_sec_lo" type="uint"
 | 
				
			||||||
 | 
					           summary="low 32 bits of the seconds part of the timestamp"/>
 | 
				
			||||||
 | 
					      <arg name="tv_nsec" type="uint"
 | 
				
			||||||
 | 
					           summary="nanoseconds part of the timestamp"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="ready">
 | 
				
			||||||
 | 
					      <description summary="frame is available for reading">
 | 
				
			||||||
 | 
					        Called as soon as the frame is copied, indicating it is available
 | 
				
			||||||
 | 
					        for reading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The buffer may be re-used by the client after this event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        After receiving this event, the client must destroy the object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="failure_reason">
 | 
				
			||||||
 | 
					      <entry name="unknown" value="0">
 | 
				
			||||||
 | 
					        <description summary="unknown runtime error">
 | 
				
			||||||
 | 
					          An unspecified runtime error has occurred. The client may retry.
 | 
				
			||||||
 | 
					        </description>
 | 
				
			||||||
 | 
					      </entry>
 | 
				
			||||||
 | 
					      <entry name="buffer_constraints" value="1">
 | 
				
			||||||
 | 
					        <description summary="buffer constraints mismatch">
 | 
				
			||||||
 | 
					          The buffer submitted by the client doesn't match the latest session
 | 
				
			||||||
 | 
					          constraints. The client should re-allocate its buffers and retry.
 | 
				
			||||||
 | 
					        </description>
 | 
				
			||||||
 | 
					      </entry>
 | 
				
			||||||
 | 
					      <entry name="stopped" value="2">
 | 
				
			||||||
 | 
					        <description summary="session is no longer available">
 | 
				
			||||||
 | 
					          The session has stopped. See ext_image_copy_capture_session_v1.stopped.
 | 
				
			||||||
 | 
					        </description>
 | 
				
			||||||
 | 
					      </entry>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="failed">
 | 
				
			||||||
 | 
					      <description summary="capture failed">
 | 
				
			||||||
 | 
					        This event indicates that the attempted frame copy has failed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        After receiving this event, the client must destroy the object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="reason" type="uint" enum="failure_reason"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="ext_image_copy_capture_cursor_session_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="cursor capture session">
 | 
				
			||||||
 | 
					      This object represents a cursor capture session. It extends the base
 | 
				
			||||||
 | 
					      capture session with cursor-specific metadata.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="duplicate_session" value="1" summary="get_captuerer_session sent twice"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="delete this object">
 | 
				
			||||||
 | 
					        Destroys the session. This request can be sent at any time by the
 | 
				
			||||||
 | 
					        client.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request doesn't affect ext_image_copy_capture_frame_v1 objects created by
 | 
				
			||||||
 | 
					        this object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="get_capture_session">
 | 
				
			||||||
 | 
					      <description summary="get image copy captuerer session">
 | 
				
			||||||
 | 
					        Gets the image copy capture session for this cursor session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The session will produce frames of the cursor image. The compositor may
 | 
				
			||||||
 | 
					        pause the session when the cursor leaves the captured area.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request must not be sent more than once, or else the
 | 
				
			||||||
 | 
					        duplicate_session protocol error is raised.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="session" type="new_id" interface="ext_image_copy_capture_session_v1"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="enter">
 | 
				
			||||||
 | 
					      <description summary="cursor entered captured area">
 | 
				
			||||||
 | 
					        Sent when a cursor enters the captured area. It shall be generated
 | 
				
			||||||
 | 
					        before the "position" and "hotspot" events when and only when a cursor
 | 
				
			||||||
 | 
					        enters the area.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The cursor enters the captured area when the cursor image intersects
 | 
				
			||||||
 | 
					        with the captured area. Note, this is different from e.g.
 | 
				
			||||||
 | 
					        wl_pointer.enter.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="leave">
 | 
				
			||||||
 | 
					      <description summary="cursor left captured area">
 | 
				
			||||||
 | 
					        Sent when a cursor leaves the captured area. No "position" or "hotspot"
 | 
				
			||||||
 | 
					        event is generated for the cursor until the cursor enters the captured
 | 
				
			||||||
 | 
					        area again.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="position">
 | 
				
			||||||
 | 
					      <description summary="position changed">
 | 
				
			||||||
 | 
					        Cursors outside the image capture source do not get captured and no
 | 
				
			||||||
 | 
					        event will be generated for them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The given position is the position of the cursor's hotspot and it is
 | 
				
			||||||
 | 
					        relative to the main buffer's top left corner in transformed buffer
 | 
				
			||||||
 | 
					        pixel coordinates. The coordinates may be negative or greater than the
 | 
				
			||||||
 | 
					        main buffer size.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="x" type="int" summary="position x coordinates"/>
 | 
				
			||||||
 | 
					      <arg name="y" type="int" summary="position y coordinates"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="hotspot">
 | 
				
			||||||
 | 
					      <description summary="hotspot changed">
 | 
				
			||||||
 | 
					        The hotspot describes the offset between the cursor image and the
 | 
				
			||||||
 | 
					        position of the input device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The given coordinates are the hotspot's offset from the origin in
 | 
				
			||||||
 | 
					        buffer coordinates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Clients should not apply the hotspot immediately: the hotspot becomes
 | 
				
			||||||
 | 
					        effective when the next ext_image_copy_capture_frame_v1.ready event is received.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Compositors may delay this event until the client captures a new frame.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="x" type="int" summary="hotspot x coordinates"/>
 | 
				
			||||||
 | 
					      <arg name="y" type="int" summary="hotspot y coordinates"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					</protocol>
 | 
				
			||||||
@ -0,0 +1,252 @@
 | 
				
			|||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wayland-client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ext-image-capture-source-v1-protocol.h"
 | 
				
			||||||
 | 
					#include "ext-image-copy-capture-v1-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "rif.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ASSERT(cond, msg)\
 | 
				
			||||||
 | 
					  if(!(cond)) {\
 | 
				
			||||||
 | 
					    fprintf(stderr, "Runtime assertion %s at %s:%d failed: %s\n", #cond, __FILE__, __LINE__, msg);\
 | 
				
			||||||
 | 
					    exit(-1);\
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Not included in any standard header
 | 
				
			||||||
 | 
					// Thus, declaring manually.
 | 
				
			||||||
 | 
					// See memfd_create(2).
 | 
				
			||||||
 | 
					int memfd_create(const char* name, unsigned int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct image_data {
 | 
				
			||||||
 | 
					  uint32_t width;
 | 
				
			||||||
 | 
					  uint32_t height;
 | 
				
			||||||
 | 
					  uint32_t shm_format;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wl_output* stream_output = NULL; 
 | 
				
			||||||
 | 
					struct wl_shm* wl_shm = NULL;
 | 
				
			||||||
 | 
					struct wl_buffer* frame_buffer = NULL;
 | 
				
			||||||
 | 
					struct ext_output_image_capture_source_manager_v1* output_source_manager = NULL;
 | 
				
			||||||
 | 
					struct ext_image_copy_capture_manager_v1* capture_manager = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void* shm_data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct image_data img_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t is_frame_ready = 0;
 | 
				
			||||||
 | 
					uint8_t is_capture_ready = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t buf_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_global(
 | 
				
			||||||
 | 
					    void* data, 
 | 
				
			||||||
 | 
					    struct wl_registry* registry, 
 | 
				
			||||||
 | 
					    uint32_t name,
 | 
				
			||||||
 | 
					    const char* interface, 
 | 
				
			||||||
 | 
					    uint32_t version) {
 | 
				
			||||||
 | 
					  if(strcmp(interface, wl_output_interface.name) == 0) {
 | 
				
			||||||
 | 
					    stream_output = wl_registry_bind(registry, name, &wl_output_interface, version);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if(strcmp(interface, wl_shm_interface.name) == 0) {
 | 
				
			||||||
 | 
					    wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, version);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if(strcmp(interface, ext_output_image_capture_source_manager_v1_interface.name) == 0) {
 | 
				
			||||||
 | 
					    output_source_manager = wl_registry_bind(registry, name, &ext_output_image_capture_source_manager_v1_interface, version);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if(strcmp(interface, ext_image_copy_capture_manager_v1_interface.name) == 0) {
 | 
				
			||||||
 | 
					    capture_manager = wl_registry_bind(registry, name, &ext_image_copy_capture_manager_v1_interface, version);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_global_remove(
 | 
				
			||||||
 | 
					    void* data,
 | 
				
			||||||
 | 
					    struct wl_registry* registry,
 | 
				
			||||||
 | 
					    uint32_t name) {
 | 
				
			||||||
 | 
						// Who cares
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct wl_registry_listener reg_callbacks = {
 | 
				
			||||||
 | 
						.global = handle_global,
 | 
				
			||||||
 | 
						.global_remove = handle_global_remove,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void buffer_size(void *data,
 | 
				
			||||||
 | 
					        struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1,
 | 
				
			||||||
 | 
					        uint32_t width,
 | 
				
			||||||
 | 
					        uint32_t height) {
 | 
				
			||||||
 | 
					  printf("x: %d, y: %d\n", width, height);
 | 
				
			||||||
 | 
					  img_data.width = width;
 | 
				
			||||||
 | 
					  img_data.height = height;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void shm_format(void *data,
 | 
				
			||||||
 | 
					       struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1,
 | 
				
			||||||
 | 
					       uint32_t format) {
 | 
				
			||||||
 | 
					  img_data.shm_format = format;
 | 
				
			||||||
 | 
					  ASSERT(format == WL_SHM_FORMAT_XBGR8888 || format == WL_SHM_FORMAT_ABGR8888, "Unsupported buffer format.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dmabuf_device(void *data,
 | 
				
			||||||
 | 
					          struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1,
 | 
				
			||||||
 | 
					          struct wl_array *device) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dmabuf_format(void *data,
 | 
				
			||||||
 | 
					          struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1,
 | 
				
			||||||
 | 
					          uint32_t format,
 | 
				
			||||||
 | 
					          struct wl_array *modifiers) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void done(void *data,
 | 
				
			||||||
 | 
					       struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1) {
 | 
				
			||||||
 | 
					  const int shm_fd = memfd_create("wl_shm data", 0);
 | 
				
			||||||
 | 
					  ASSERT(shm_fd != -1, "Failed to create memfd.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Format is hardcoded to chan width 4
 | 
				
			||||||
 | 
					  const uint32_t chan_width = 4;
 | 
				
			||||||
 | 
					  const uint32_t stride = img_data.width * chan_width;
 | 
				
			||||||
 | 
					  buf_size = img_data.height * stride;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT(ftruncate(shm_fd, buf_size) != -1, "Failed to ftruncate the memfd.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  shm_data = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
 | 
				
			||||||
 | 
					  ASSERT(shm_data != MAP_FAILED, "Failed to mmap the memfd.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct wl_shm_pool* pool = wl_shm_create_pool(wl_shm, shm_fd, buf_size);
 | 
				
			||||||
 | 
					  ASSERT(pool != NULL, "Failed to create the wl_shm_pool.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  frame_buffer = wl_shm_pool_create_buffer(pool, 0, img_data.width, img_data.height, stride, img_data.shm_format);
 | 
				
			||||||
 | 
					  ASSERT(frame_buffer != NULL, "Failed to create the wl_buffer.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  is_frame_ready = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void stopped(void *data,
 | 
				
			||||||
 | 
					    struct ext_image_copy_capture_session_v1 *ext_image_copy_capture_session_v1) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct ext_image_copy_capture_session_v1_listener capture_listener = {
 | 
				
			||||||
 | 
					  .buffer_size = buffer_size,
 | 
				
			||||||
 | 
					  .shm_format = shm_format,
 | 
				
			||||||
 | 
					  .dmabuf_device = dmabuf_device,
 | 
				
			||||||
 | 
					  .dmabuf_format = dmabuf_format,
 | 
				
			||||||
 | 
					  .done = done,
 | 
				
			||||||
 | 
					  .stopped = stopped
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void transform(void *data,
 | 
				
			||||||
 | 
					      struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1,
 | 
				
			||||||
 | 
					      uint32_t transform) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void damage(void *data,
 | 
				
			||||||
 | 
					         struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1,
 | 
				
			||||||
 | 
					         int32_t x,
 | 
				
			||||||
 | 
					         int32_t y,
 | 
				
			||||||
 | 
					         int32_t width,
 | 
				
			||||||
 | 
					         int32_t height) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void presentation_time(void *data,
 | 
				
			||||||
 | 
					        struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1,
 | 
				
			||||||
 | 
					        uint32_t tv_sec_hi,
 | 
				
			||||||
 | 
					        uint32_t tv_sec_lo,
 | 
				
			||||||
 | 
					        uint32_t tv_nsec) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void ready(void *data,
 | 
				
			||||||
 | 
					        struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1) {
 | 
				
			||||||
 | 
					  is_capture_ready = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void failed(void *data,
 | 
				
			||||||
 | 
					         struct ext_image_copy_capture_frame_v1 *ext_image_copy_capture_frame_v1,
 | 
				
			||||||
 | 
					         uint32_t reason) {
 | 
				
			||||||
 | 
					  switch(reason) {
 | 
				
			||||||
 | 
					    case 0:
 | 
				
			||||||
 | 
					      printf("Capture failed. Reason: Unknown Runtime Error.");
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 1:
 | 
				
			||||||
 | 
					      printf("Capture failed. Reason: Buffer Constraints Mismatch.");
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 2:
 | 
				
			||||||
 | 
					      printf("Capture failed. Reason: Session Is No Longer Available.");
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct ext_image_copy_capture_frame_v1_listener frame_listener = {
 | 
				
			||||||
 | 
					  .transform = transform,
 | 
				
			||||||
 | 
					  .damage = damage,
 | 
				
			||||||
 | 
					  .presentation_time = presentation_time,
 | 
				
			||||||
 | 
					  .ready = ready,
 | 
				
			||||||
 | 
					  .failed = failed
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
					  struct wl_display* dpy = wl_display_connect(NULL);
 | 
				
			||||||
 | 
					  ASSERT(dpy != NULL, "Unable to connect to Wayland");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct wl_registry* registry = wl_display_get_registry(dpy);
 | 
				
			||||||
 | 
						wl_registry_add_listener(registry, ®_callbacks, NULL);
 | 
				
			||||||
 | 
						wl_display_roundtrip(dpy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT(wl_shm != NULL, "core.wl_shm not supported.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT(stream_output != NULL, "No outputs found!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT(output_source_manager != NULL, "ext-image-capture-source-v1.ext_output_image_capture_source_manager_v1 not supported.");
 | 
				
			||||||
 | 
					  ASSERT(capture_manager != NULL, "ext-image-copy-capture-v1.ext_image_copy_capture_manager_v1 not supported.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct ext_image_capture_source_v1* capture_source = 
 | 
				
			||||||
 | 
					    ext_output_image_capture_source_manager_v1_create_source(output_source_manager, stream_output);
 | 
				
			||||||
 | 
					  ASSERT(capture_source != NULL, "Failed creating a source for the default output!")
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  struct ext_image_copy_capture_session_v1* capture_session =
 | 
				
			||||||
 | 
					    ext_image_copy_capture_manager_v1_create_session(capture_manager, capture_source, EXT_IMAGE_COPY_CAPTURE_MANAGER_V1_OPTIONS_PAINT_CURSORS);
 | 
				
			||||||
 | 
					  ASSERT(capture_session != NULL, "Failed creating a session for the capture!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ext_image_copy_capture_session_v1_add_listener(capture_session, &capture_listener, NULL);
 | 
				
			||||||
 | 
					  wl_display_roundtrip(dpy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while(is_frame_ready == 0 && wl_display_dispatch(dpy) != -1) {
 | 
				
			||||||
 | 
					    // Empty
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct ext_image_copy_capture_frame_v1* frame = ext_image_copy_capture_session_v1_create_frame(capture_session);
 | 
				
			||||||
 | 
					  ASSERT(frame != NULL, "Failed to create frame!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ext_image_copy_capture_frame_v1_add_listener(frame, &frame_listener, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ext_image_copy_capture_frame_v1_attach_buffer(frame, frame_buffer);
 | 
				
			||||||
 | 
					  ext_image_copy_capture_frame_v1_damage_buffer(frame, 0, 0, img_data.width, img_data.height);
 | 
				
			||||||
 | 
					  ext_image_copy_capture_frame_v1_capture(frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wl_display_roundtrip(dpy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while(is_capture_ready == 0 && wl_display_dispatch(dpy) != -1) {
 | 
				
			||||||
 | 
					    // Empty
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  printf("Saving screenshot.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // void write_rif_little(char* path, uint32_t width, uint32_t size, uint8_t format, void* data) {
 | 
				
			||||||
 | 
					  // Thanks to endianess shenanigans, ABGR/XBGR is RGBA. 
 | 
				
			||||||
 | 
					  write_rif_little("out.rif", img_data.width, buf_size, RIF_FORMAT_R8G8B8A8, shm_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ext_image_copy_capture_frame_v1_destroy(frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					typedef struct rif {
 | 
				
			||||||
 | 
					  // "lifV0001"
 | 
				
			||||||
 | 
					  // "rifV0001"
 | 
				
			||||||
 | 
					  char     magic_num[8]; // Big Endian. UTF-8 Encoded. 6C 69 66 56 30 30 30 31
 | 
				
			||||||
 | 
					  uint64_t width;        // Big Endian
 | 
				
			||||||
 | 
					  uint8_t  format;
 | 
				
			||||||
 | 
					  uint8_t  data[];
 | 
				
			||||||
 | 
					} rif_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RIF_MAGIC_LITTLE {'l', 'i', 'f', 'V', '0', '0', '0', '1'}
 | 
				
			||||||
 | 
					#define RIF_MAGIC_BIG    {'r', 'i', 'f', 'V', '0', '0', '0', '1'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RIF_FORMAT_R8G8B8   0
 | 
				
			||||||
 | 
					#define RIF_FORMAT_R8G8B8A8 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void write_rif_little(char* path, uint32_t width, uint32_t size, uint8_t format, void* data) {
 | 
				
			||||||
 | 
					#define IMG_SIZE 17 + size // 17 is the size of raw_img excluding the data field
 | 
				
			||||||
 | 
					  rif_t* img = malloc(IMG_SIZE);
 | 
				
			||||||
 | 
					  char magic[] = RIF_MAGIC_LITTLE;
 | 
				
			||||||
 | 
					  memcpy(((char*)img)+0, magic, 8);
 | 
				
			||||||
 | 
					  img->width = width;
 | 
				
			||||||
 | 
					  img->format = format;
 | 
				
			||||||
 | 
					  memcpy(((char*)img)+17, data, size);
 | 
				
			||||||
 | 
					  FILE* output_file = fopen(path, "w");
 | 
				
			||||||
 | 
					  fwrite(img, 1, IMG_SIZE, output_file);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue