mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-22 06:35:57 +01:00
Fix CI with libpipewire02, libdrm. Remove png.h unused import. Cleanup style.
This commit is contained in:
parent
c0da39f022
commit
45699637d1
15 changed files with 480 additions and 514 deletions
|
@ -5,7 +5,8 @@ packages:
|
||||||
- meson
|
- meson
|
||||||
- wayland
|
- wayland
|
||||||
- wayland-protocols
|
- wayland-protocols
|
||||||
- pipewire
|
- libpipewire02
|
||||||
|
- libdrm
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/emersion/xdg-desktop-portal-wlr
|
- https://github.com/emersion/xdg-desktop-portal-wlr
|
||||||
tasks:
|
tasks:
|
||||||
|
|
|
@ -1,27 +1,20 @@
|
||||||
#ifndef LOGGER_H
|
#ifndef LOGGER_H
|
||||||
#define LOGGER_H
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
enum LOGLEVEL {
|
enum LOGLEVEL { QUIET, ERROR, WARN, INFO, DEBUG, TRACE };
|
||||||
QUIET,
|
|
||||||
ERROR,
|
|
||||||
WARN,
|
|
||||||
INFO,
|
|
||||||
DEBUG,
|
|
||||||
TRACE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct logger_properties{
|
struct logger_properties {
|
||||||
enum LOGLEVEL level;
|
enum LOGLEVEL level;
|
||||||
FILE *__restrict__ dst;
|
FILE *dst;
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_logger(FILE *__restrict__ dst, enum LOGLEVEL level);
|
void init_logger(FILE *dst, enum LOGLEVEL level);
|
||||||
enum LOGLEVEL get_loglevel(const char *level);
|
enum LOGLEVEL get_loglevel(const char *level);
|
||||||
void logprint(enum LOGLEVEL level, char *msg, ...);
|
void logprint(enum LOGLEVEL level, char *msg, ...);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef SCREENCAST_COMMON_H
|
#ifndef SCREENCAST_COMMON_H
|
||||||
#define SCREENCAST_COMMON_H
|
#define SCREENCAST_COMMON_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
#include <spa/param/video/format-utils.h>
|
#include <spa/param/video/format-utils.h>
|
||||||
#include <libdrm/drm_fourcc.h>
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
@ -24,7 +25,6 @@ struct simple_frame {
|
||||||
uint32_t tv_nsec;
|
uint32_t tv_nsec;
|
||||||
enum wl_shm_format format;
|
enum wl_shm_format format;
|
||||||
struct damage *damage;
|
struct damage *damage;
|
||||||
|
|
||||||
struct wl_buffer *buffer;
|
struct wl_buffer *buffer;
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
@ -38,7 +38,6 @@ struct pwr_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct screencast_context {
|
struct screencast_context {
|
||||||
|
|
||||||
// pipewire
|
// pipewire
|
||||||
struct pwr_type type;
|
struct pwr_type type;
|
||||||
struct pw_loop *loop;
|
struct pw_loop *loop;
|
||||||
|
@ -97,6 +96,5 @@ struct wayland_output {
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t pipewire_from_wl_shm(void *data);
|
uint32_t pipewire_from_wl_shm(void *data);
|
||||||
char *strdup(const char *src);
|
|
||||||
|
|
||||||
#endif /* SCREENCAST_COMMON_H */
|
#endif /* SCREENCAST_COMMON_H */
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <png.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -27,9 +26,10 @@ void wlr_frame_free(struct xdpw_state *state);
|
||||||
int wlr_screencopy_init(struct xdpw_state *state);
|
int wlr_screencopy_init(struct xdpw_state *state);
|
||||||
void wlr_screencopy_uninit(struct screencast_context *ctx);
|
void wlr_screencopy_uninit(struct screencast_context *ctx);
|
||||||
|
|
||||||
struct wayland_output *wlr_output_find_by_name(struct wl_list *output_list, const char* name);
|
struct wayland_output *wlr_output_find_by_name(struct wl_list *output_list,
|
||||||
|
const char *name);
|
||||||
struct wayland_output *wlr_output_find(struct screencast_context *ctx,
|
struct wayland_output *wlr_output_find(struct screencast_context *ctx,
|
||||||
struct wl_output *out, uint32_t id);
|
struct wl_output *out, uint32_t id);
|
||||||
struct wayland_output *wlr_output_first(struct wl_list *output_list);
|
struct wayland_output *wlr_output_first(struct wl_list *output_list);
|
||||||
|
|
||||||
void wlr_register_cb(struct xdpw_state *state);
|
void wlr_register_cb(struct xdpw_state *state);
|
||||||
|
|
|
@ -8,7 +8,6 @@ project(
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
'warning_level=2',
|
'warning_level=2',
|
||||||
'werror=true',
|
'werror=true',
|
||||||
'debug=true',
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,207 +1,207 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<protocol name="wlr_screencopy_unstable_v1">
|
<protocol name="wlr_screencopy_unstable_v1">
|
||||||
<copyright>
|
<copyright>
|
||||||
Copyright © 2018 Simon Ser
|
Copyright © 2018 Simon Ser
|
||||||
Copyright © 2019 Andri Yngvason
|
Copyright © 2019 Andri Yngvason
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
to deal in the Software without restriction, including without limitation
|
to deal in the Software without restriction, including without limitation
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
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:
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice (including the next
|
The above copyright notice and this permission notice (including the next
|
||||||
paragraph) shall be included in all copies or substantial portions of the
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
Software.
|
Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
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
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
DEALINGS IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
<description summary="screen content capturing on client buffers">
|
<description summary="screen content capturing on client buffers">
|
||||||
This protocol allows clients to ask the compositor to copy part of the
|
This protocol allows clients to ask the compositor to copy part of the
|
||||||
screen content to a client buffer.
|
screen content to a client buffer.
|
||||||
|
|
||||||
Warning! The protocol described in this file is experimental and
|
Warning! The protocol described in this file is experimental and
|
||||||
backward incompatible changes may be made. Backward compatible changes
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
may be added together with the corresponding interface version bump.
|
may be added together with the corresponding interface version bump.
|
||||||
Backward incompatible changes are done by bumping the version number in
|
Backward incompatible changes are done by bumping the version number in
|
||||||
the protocol and interface names and resetting the interface version.
|
the protocol and interface names and resetting the interface version.
|
||||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||||
version number in the protocol and interface names are removed and the
|
version number in the protocol and interface names are removed and the
|
||||||
interface version number is reset.
|
interface version number is reset.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<interface name="zwlr_screencopy_manager_v1" version="2">
|
<interface name="zwlr_screencopy_manager_v1" version="2">
|
||||||
<description summary="manager to inform clients and begin capturing">
|
<description summary="manager to inform clients and begin capturing">
|
||||||
This object is a manager which offers requests to start capturing from a
|
This object is a manager which offers requests to start capturing from a
|
||||||
source.
|
source.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<request name="capture_output">
|
<request name="capture_output">
|
||||||
<description summary="capture an output">
|
<description summary="capture an output">
|
||||||
Capture the next frame of an entire output.
|
Capture the next frame of an entire output.
|
||||||
</description>
|
</description>
|
||||||
<arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/>
|
<arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/>
|
||||||
<arg name="overlay_cursor" type="int"
|
<arg name="overlay_cursor" type="int"
|
||||||
summary="composite cursor onto the frame"/>
|
summary="composite cursor onto the frame"/>
|
||||||
<arg name="output" type="object" interface="wl_output"/>
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<request name="capture_output_region">
|
<request name="capture_output_region">
|
||||||
<description summary="capture an output's region">
|
<description summary="capture an output's region">
|
||||||
Capture the next frame of an output's region.
|
Capture the next frame of an output's region.
|
||||||
|
|
||||||
The region is given in output logical coordinates, see
|
The region is given in output logical coordinates, see
|
||||||
xdg_output.logical_size. The region will be clipped to the output's
|
xdg_output.logical_size. The region will be clipped to the output's
|
||||||
extents.
|
extents.
|
||||||
</description>
|
</description>
|
||||||
<arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/>
|
<arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/>
|
||||||
<arg name="overlay_cursor" type="int"
|
<arg name="overlay_cursor" type="int"
|
||||||
summary="composite cursor onto the frame"/>
|
summary="composite cursor onto the frame"/>
|
||||||
<arg name="output" type="object" interface="wl_output"/>
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
<arg name="x" type="int"/>
|
<arg name="x" type="int"/>
|
||||||
<arg name="y" type="int"/>
|
<arg name="y" type="int"/>
|
||||||
<arg name="width" type="int"/>
|
<arg name="width" type="int"/>
|
||||||
<arg name="height" type="int"/>
|
<arg name="height" type="int"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
<request name="destroy" type="destructor">
|
||||||
<description summary="destroy the manager">
|
<description summary="destroy the manager">
|
||||||
All objects created by the manager will still remain valid, until their
|
All objects created by the manager will still remain valid, until their
|
||||||
appropriate destroy request has been called.
|
appropriate destroy request has been called.
|
||||||
</description>
|
</description>
|
||||||
</request>
|
</request>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="zwlr_screencopy_frame_v1" version="2">
|
<interface name="zwlr_screencopy_frame_v1" version="2">
|
||||||
<description summary="a frame ready for copy">
|
<description summary="a frame ready for copy">
|
||||||
This object represents a single frame.
|
This object represents a single frame.
|
||||||
|
|
||||||
When created, a "buffer" event will be sent. The client will then be able
|
When created, a "buffer" event will be sent. The client will then be able
|
||||||
to send a "copy" request. If the capture is successful, the compositor
|
to send a "copy" request. If the capture is successful, the compositor
|
||||||
will send a "flags" followed by a "ready" event.
|
will send a "flags" followed by a "ready" event.
|
||||||
|
|
||||||
If the capture failed, the "failed" event is sent. This can happen anytime
|
If the capture failed, the "failed" event is sent. This can happen anytime
|
||||||
before the "ready" event.
|
before the "ready" event.
|
||||||
|
|
||||||
Once either a "ready" or a "failed" event is received, the client should
|
Once either a "ready" or a "failed" event is received, the client should
|
||||||
destroy the frame.
|
destroy the frame.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<event name="buffer">
|
<event name="buffer">
|
||||||
<description summary="buffer information">
|
<description summary="buffer information">
|
||||||
Provides information about the frame's buffer. This event is sent once
|
Provides information about the frame's buffer. This event is sent once
|
||||||
as soon as the frame is created.
|
as soon as the frame is created.
|
||||||
|
|
||||||
The client should then create a buffer with the provided attributes, and
|
The client should then create a buffer with the provided attributes, and
|
||||||
send a "copy" request.
|
send a "copy" request.
|
||||||
</description>
|
</description>
|
||||||
<arg name="format" type="uint" summary="buffer format"/>
|
<arg name="format" type="uint" summary="buffer format"/>
|
||||||
<arg name="width" type="uint" summary="buffer width"/>
|
<arg name="width" type="uint" summary="buffer width"/>
|
||||||
<arg name="height" type="uint" summary="buffer height"/>
|
<arg name="height" type="uint" summary="buffer height"/>
|
||||||
<arg name="stride" type="uint" summary="buffer stride"/>
|
<arg name="stride" type="uint" summary="buffer stride"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<request name="copy">
|
<request name="copy">
|
||||||
<description summary="copy the frame">
|
<description summary="copy the frame">
|
||||||
Copy the frame to the supplied buffer. The buffer must have a the
|
Copy the frame to the supplied buffer. The buffer must have a the
|
||||||
correct size, see zwlr_screencopy_frame_v1.buffer. The buffer needs to
|
correct size, see zwlr_screencopy_frame_v1.buffer. The buffer needs to
|
||||||
have a supported format.
|
have a supported format.
|
||||||
|
|
||||||
If the frame is successfully copied, a "flags" and a "ready" events are
|
If the frame is successfully copied, a "flags" and a "ready" events are
|
||||||
sent. Otherwise, a "failed" event is sent.
|
sent. Otherwise, a "failed" event is sent.
|
||||||
</description>
|
</description>
|
||||||
<arg name="buffer" type="object" interface="wl_buffer"/>
|
<arg name="buffer" type="object" interface="wl_buffer"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<enum name="error">
|
<enum name="error">
|
||||||
<entry name="already_used" value="0"
|
<entry name="already_used" value="0"
|
||||||
summary="the object has already been used to copy a wl_buffer"/>
|
summary="the object has already been used to copy a wl_buffer"/>
|
||||||
<entry name="invalid_buffer" value="1"
|
<entry name="invalid_buffer" value="1"
|
||||||
summary="buffer attributes are invalid"/>
|
summary="buffer attributes are invalid"/>
|
||||||
</enum>
|
</enum>
|
||||||
|
|
||||||
<enum name="flags" bitfield="true">
|
<enum name="flags" bitfield="true">
|
||||||
<entry name="y_invert" value="1" summary="contents are y-inverted"/>
|
<entry name="y_invert" value="1" summary="contents are y-inverted"/>
|
||||||
</enum>
|
</enum>
|
||||||
|
|
||||||
<event name="flags">
|
<event name="flags">
|
||||||
<description summary="frame flags">
|
<description summary="frame flags">
|
||||||
Provides flags about the frame. This event is sent once before the
|
Provides flags about the frame. This event is sent once before the
|
||||||
"ready" event.
|
"ready" event.
|
||||||
</description>
|
</description>
|
||||||
<arg name="flags" type="uint" enum="flags" summary="frame flags"/>
|
<arg name="flags" type="uint" enum="flags" summary="frame flags"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="ready">
|
<event name="ready">
|
||||||
<description summary="indicates frame is available for reading">
|
<description summary="indicates frame is available for reading">
|
||||||
Called as soon as the frame is copied, indicating it is available
|
Called as soon as the frame is copied, indicating it is available
|
||||||
for reading. This event includes the time at which presentation happened
|
for reading. This event includes the time at which presentation happened
|
||||||
at.
|
at.
|
||||||
|
|
||||||
The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
|
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
|
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,
|
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,
|
and the additional fractional part in tv_nsec as nanoseconds. Hence,
|
||||||
for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part
|
for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part
|
||||||
may have an arbitrary offset at start.
|
may have an arbitrary offset at start.
|
||||||
|
|
||||||
After receiving this event, the client should destroy the object.
|
After receiving this event, the client should destroy the object.
|
||||||
</description>
|
</description>
|
||||||
<arg name="tv_sec_hi" type="uint"
|
<arg name="tv_sec_hi" type="uint"
|
||||||
summary="high 32 bits of the seconds part of the timestamp"/>
|
summary="high 32 bits of the seconds part of the timestamp"/>
|
||||||
<arg name="tv_sec_lo" type="uint"
|
<arg name="tv_sec_lo" type="uint"
|
||||||
summary="low 32 bits of the seconds part of the timestamp"/>
|
summary="low 32 bits of the seconds part of the timestamp"/>
|
||||||
<arg name="tv_nsec" type="uint"
|
<arg name="tv_nsec" type="uint"
|
||||||
summary="nanoseconds part of the timestamp"/>
|
summary="nanoseconds part of the timestamp"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="failed">
|
<event name="failed">
|
||||||
<description summary="frame copy failed">
|
<description summary="frame copy failed">
|
||||||
This event indicates that the attempted frame copy has failed.
|
This event indicates that the attempted frame copy has failed.
|
||||||
|
|
||||||
After receiving this event, the client should destroy the object.
|
After receiving this event, the client should destroy the object.
|
||||||
</description>
|
</description>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
<request name="destroy" type="destructor">
|
||||||
<description summary="delete this object, used or not">
|
<description summary="delete this object, used or not">
|
||||||
Destroys the frame. This request can be sent at any time by the client.
|
Destroys the frame. This request can be sent at any time by the client.
|
||||||
</description>
|
</description>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<!-- Version 2 additions -->
|
<!-- Version 2 additions -->
|
||||||
<request name="copy_with_damage" since="2">
|
<request name="copy_with_damage" since="2">
|
||||||
<description summary="copy the frame when it's damaged">
|
<description summary="copy the frame when it's damaged">
|
||||||
Same as copy, except it waits until there is damage to copy.
|
Same as copy, except it waits until there is damage to copy.
|
||||||
</description>
|
</description>
|
||||||
<arg name="buffer" type="object" interface="wl_buffer"/>
|
<arg name="buffer" type="object" interface="wl_buffer"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<event name="damage" since="2">
|
<event name="damage" since="2">
|
||||||
<description summary="carries the coordinates of the damaged region">
|
<description summary="carries the coordinates of the damaged region">
|
||||||
This event is sent right before the ready event when copy_with_damage is
|
This event is sent right before the ready event when copy_with_damage is
|
||||||
requested. It may be generated multiple times for each copy_with_damage
|
requested. It may be generated multiple times for each copy_with_damage
|
||||||
request.
|
request.
|
||||||
|
|
||||||
The arguments describe a box around an area that has changed since the
|
The arguments describe a box around an area that has changed since the
|
||||||
last copy request that was derived from the current screencopy manager
|
last copy request that was derived from the current screencopy manager
|
||||||
instance.
|
instance.
|
||||||
|
|
||||||
The union of all regions received between the call to copy_with_damage
|
The union of all regions received between the call to copy_with_damage
|
||||||
and a ready event is the total damage since the prior ready event.
|
and a ready event is the total damage since the prior ready event.
|
||||||
</description>
|
</description>
|
||||||
<arg name="x" type="uint" summary="damaged x coordinates"/>
|
<arg name="x" type="uint" summary="damaged x coordinates"/>
|
||||||
<arg name="y" type="uint" summary="damaged y coordinates"/>
|
<arg name="y" type="uint" summary="damaged y coordinates"/>
|
||||||
<arg name="width" type="uint" summary="current width"/>
|
<arg name="width" type="uint" summary="current width"/>
|
||||||
<arg name="height" type="uint" summary="current height"/>
|
<arg name="height" type="uint" summary="current height"/>
|
||||||
</event>
|
</event>
|
||||||
</interface>
|
</interface>
|
||||||
</protocol>
|
</protocol>
|
||||||
|
|
|
@ -1,119 +1,119 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<protocol name="xdg_output_unstable_v1">
|
<protocol name="xdg_output_unstable_v1">
|
||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
Copyright © 2017 Red Hat Inc.
|
Copyright © 2017 Red Hat Inc.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
to deal in the Software without restriction, including without limitation
|
to deal in the Software without restriction, including without limitation
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
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:
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice (including the next
|
The above copyright notice and this permission notice (including the next
|
||||||
paragraph) shall be included in all copies or substantial portions of the
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
Software.
|
Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
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
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
DEALINGS IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
<description summary="Protocol to describe output regions">
|
<description summary="Protocol to describe output regions">
|
||||||
This protocol aims at describing outputs in a way which is more in line
|
This protocol aims at describing outputs in a way which is more in line
|
||||||
with the concept of an output on desktop oriented systems.
|
with the concept of an output on desktop oriented systems.
|
||||||
|
|
||||||
Some information are more specific to the concept of an output for
|
Some information are more specific to the concept of an output for
|
||||||
a desktop oriented system and may not make sense in other applications,
|
a desktop oriented system and may not make sense in other applications,
|
||||||
such as IVI systems for example.
|
such as IVI systems for example.
|
||||||
|
|
||||||
Typically, the global compositor space on a desktop system is made of
|
Typically, the global compositor space on a desktop system is made of
|
||||||
a contiguous or overlapping set of rectangular regions.
|
a contiguous or overlapping set of rectangular regions.
|
||||||
|
|
||||||
Some of the information provided in this protocol might be identical
|
Some of the information provided in this protocol might be identical
|
||||||
to their counterparts already available from wl_output, in which case
|
to their counterparts already available from wl_output, in which case
|
||||||
the information provided by this protocol should be preferred to their
|
the information provided by this protocol should be preferred to their
|
||||||
equivalent in wl_output. The goal is to move the desktop specific
|
equivalent in wl_output. The goal is to move the desktop specific
|
||||||
concepts (such as output location within the global compositor space,
|
concepts (such as output location within the global compositor space,
|
||||||
the connector name and types, etc.) out of the core wl_output protocol.
|
the connector name and types, etc.) out of the core wl_output protocol.
|
||||||
|
|
||||||
Warning! The protocol described in this file is experimental and
|
Warning! The protocol described in this file is experimental and
|
||||||
backward incompatible changes may be made. Backward compatible
|
backward incompatible changes may be made. Backward compatible
|
||||||
changes may be added together with the corresponding interface
|
changes may be added together with the corresponding interface
|
||||||
version bump.
|
version bump.
|
||||||
Backward incompatible changes are done by bumping the version
|
Backward incompatible changes are done by bumping the version
|
||||||
number in the protocol and interface names and resetting the
|
number in the protocol and interface names and resetting the
|
||||||
interface version. Once the protocol is to be declared stable,
|
interface version. Once the protocol is to be declared stable,
|
||||||
the 'z' prefix and the version number in the protocol and
|
the 'z' prefix and the version number in the protocol and
|
||||||
interface names are removed and the interface version number is
|
interface names are removed and the interface version number is
|
||||||
reset.
|
reset.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<interface name="zxdg_output_manager_v1" version="3">
|
<interface name="zxdg_output_manager_v1" version="3">
|
||||||
<description summary="manage xdg_output objects">
|
<description summary="manage xdg_output objects">
|
||||||
A global factory interface for xdg_output objects.
|
A global factory interface for xdg_output objects.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
<request name="destroy" type="destructor">
|
||||||
<description summary="destroy the xdg_output_manager object">
|
<description summary="destroy the xdg_output_manager object">
|
||||||
Using this request a client can tell the server that it is not
|
Using this request a client can tell the server that it is not
|
||||||
going to use the xdg_output_manager object anymore.
|
going to use the xdg_output_manager object anymore.
|
||||||
|
|
||||||
Any objects already created through this instance are not affected.
|
Any objects already created through this instance are not affected.
|
||||||
</description>
|
</description>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<request name="get_xdg_output">
|
<request name="get_xdg_output">
|
||||||
<description summary="create an xdg output from a wl_output">
|
<description summary="create an xdg output from a wl_output">
|
||||||
This creates a new xdg_output object for the given wl_output.
|
This creates a new xdg_output object for the given wl_output.
|
||||||
</description>
|
</description>
|
||||||
<arg name="id" type="new_id" interface="zxdg_output_v1"/>
|
<arg name="id" type="new_id" interface="zxdg_output_v1"/>
|
||||||
<arg name="output" type="object" interface="wl_output"/>
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
</request>
|
</request>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="zxdg_output_v1" version="3">
|
<interface name="zxdg_output_v1" version="3">
|
||||||
<description summary="compositor logical output region">
|
<description summary="compositor logical output region">
|
||||||
An xdg_output describes part of the compositor geometry.
|
An xdg_output describes part of the compositor geometry.
|
||||||
|
|
||||||
This typically corresponds to a monitor that displays part of the
|
This typically corresponds to a monitor that displays part of the
|
||||||
compositor space.
|
compositor space.
|
||||||
|
|
||||||
For objects version 3 onwards, after all xdg_output properties have been
|
For objects version 3 onwards, after all xdg_output properties have been
|
||||||
sent (when the object is created and when properties are updated), a
|
sent (when the object is created and when properties are updated), a
|
||||||
wl_output.done event is sent. This allows changes to the output
|
wl_output.done event is sent. This allows changes to the output
|
||||||
properties to be seen as atomic, even if they happen via multiple events.
|
properties to be seen as atomic, even if they happen via multiple events.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
<request name="destroy" type="destructor">
|
||||||
<description summary="destroy the xdg_output object">
|
<description summary="destroy the xdg_output object">
|
||||||
Using this request a client can tell the server that it is not
|
Using this request a client can tell the server that it is not
|
||||||
going to use the xdg_output object anymore.
|
going to use the xdg_output object anymore.
|
||||||
</description>
|
</description>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<event name="logical_position">
|
<event name="logical_position">
|
||||||
<description summary="position of the output within the global compositor space">
|
<description summary="position of the output within the global compositor space">
|
||||||
The position event describes the location of the wl_output within
|
The position event describes the location of the wl_output within
|
||||||
the global compositor space.
|
the global compositor space.
|
||||||
|
|
||||||
The logical_position event is sent after creating an xdg_output
|
The logical_position event is sent after creating an xdg_output
|
||||||
(see xdg_output_manager.get_xdg_output) and whenever the location
|
(see xdg_output_manager.get_xdg_output) and whenever the location
|
||||||
of the output changes within the global compositor space.
|
of the output changes within the global compositor space.
|
||||||
</description>
|
</description>
|
||||||
<arg name="x" type="int"
|
<arg name="x" type="int"
|
||||||
summary="x position within the global compositor space"/>
|
summary="x position within the global compositor space"/>
|
||||||
<arg name="y" type="int"
|
<arg name="y" type="int"
|
||||||
summary="y position within the global compositor space"/>
|
summary="y position within the global compositor space"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="logical_size">
|
<event name="logical_size">
|
||||||
<description summary="size of the output in the global compositor space">
|
<description summary="size of the output in the global compositor space">
|
||||||
The logical_size event describes the size of the output in the
|
The logical_size event describes the size of the output in the
|
||||||
global compositor space.
|
global compositor space.
|
||||||
|
|
||||||
|
@ -132,13 +132,13 @@
|
||||||
For example, for a wl_output mode 3840×2160 and a scale factor 2:
|
For example, for a wl_output mode 3840×2160 and a scale factor 2:
|
||||||
|
|
||||||
- A compositor not scaling the surface buffers will advertise a
|
- A compositor not scaling the surface buffers will advertise a
|
||||||
logical size of 3840×2160,
|
logical size of 3840×2160,
|
||||||
|
|
||||||
- A compositor automatically scaling the surface buffers will
|
- A compositor automatically scaling the surface buffers will
|
||||||
advertise a logical size of 1920×1080,
|
advertise a logical size of 1920×1080,
|
||||||
|
|
||||||
- A compositor using a fractional scale of 1.5 will advertise a
|
- A compositor using a fractional scale of 1.5 will advertise a
|
||||||
logical size to 2560×1620.
|
logical size to 2560×1620.
|
||||||
|
|
||||||
For example, for a wl_output mode 1920×1080 and a 90 degree rotation,
|
For example, for a wl_output mode 1920×1080 and a 90 degree rotation,
|
||||||
the compositor will advertise a logical size of 1080x1920.
|
the compositor will advertise a logical size of 1080x1920.
|
||||||
|
@ -148,15 +148,15 @@
|
||||||
size of the output changes, either as a result of a change in the
|
size of the output changes, either as a result of a change in the
|
||||||
applied scale or because of a change in the corresponding output
|
applied scale or because of a change in the corresponding output
|
||||||
mode(see wl_output.mode) or transform (see wl_output.transform).
|
mode(see wl_output.mode) or transform (see wl_output.transform).
|
||||||
</description>
|
</description>
|
||||||
<arg name="width" type="int"
|
<arg name="width" type="int"
|
||||||
summary="width in global compositor space"/>
|
summary="width in global compositor space"/>
|
||||||
<arg name="height" type="int"
|
<arg name="height" type="int"
|
||||||
summary="height in global compositor space"/>
|
summary="height in global compositor space"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="done">
|
<event name="done">
|
||||||
<description summary="all information about the output have been sent">
|
<description summary="all information about the output have been sent">
|
||||||
This event is sent after all other properties of an xdg_output
|
This event is sent after all other properties of an xdg_output
|
||||||
have been sent.
|
have been sent.
|
||||||
|
|
||||||
|
@ -166,13 +166,13 @@
|
||||||
For objects version 3 onwards, this event is deprecated. Compositors
|
For objects version 3 onwards, this event is deprecated. Compositors
|
||||||
are not required to send it anymore and must send wl_output.done
|
are not required to send it anymore and must send wl_output.done
|
||||||
instead.
|
instead.
|
||||||
</description>
|
</description>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<!-- Version 2 additions -->
|
<!-- Version 2 additions -->
|
||||||
|
|
||||||
<event name="name" since="2">
|
<event name="name" since="2">
|
||||||
<description summary="name of this output">
|
<description summary="name of this output">
|
||||||
Many compositors will assign names to their outputs, show them to the
|
Many compositors will assign names to their outputs, show them to the
|
||||||
user, allow them to be configured by name, etc. The client may wish to
|
user, allow them to be configured by name, etc. The client may wish to
|
||||||
know this name as well to offer the user similar behaviors.
|
know this name as well to offer the user similar behaviors.
|
||||||
|
@ -191,12 +191,12 @@
|
||||||
xdg_output_manager.get_xdg_output). This event is only sent once per
|
xdg_output_manager.get_xdg_output). This event is only sent once per
|
||||||
xdg_output, and the name does not change over the lifetime of the
|
xdg_output, and the name does not change over the lifetime of the
|
||||||
wl_output global.
|
wl_output global.
|
||||||
</description>
|
</description>
|
||||||
<arg name="name" type="string" summary="output name"/>
|
<arg name="name" type="string" summary="output name"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="description" since="2">
|
<event name="description" since="2">
|
||||||
<description summary="human-readable description of this output">
|
<description summary="human-readable description of this output">
|
||||||
Many compositors can produce human-readable descriptions of their
|
Many compositors can produce human-readable descriptions of their
|
||||||
outputs. The client may wish to know this description as well, to
|
outputs. The client may wish to know this description as well, to
|
||||||
communicate the user for various purposes.
|
communicate the user for various purposes.
|
||||||
|
@ -212,9 +212,9 @@
|
||||||
For objects of version 2 and lower, this event is only sent once per
|
For objects of version 2 and lower, this event is only sent once per
|
||||||
xdg_output, and the description does not change over the lifetime of
|
xdg_output, and the description does not change over the lifetime of
|
||||||
the wl_output global.
|
the wl_output global.
|
||||||
</description>
|
</description>
|
||||||
<arg name="description" type="string" summary="output description"/>
|
<arg name="description" type="string" summary="output description"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
</interface>
|
</interface>
|
||||||
</protocol>
|
</protocol>
|
||||||
|
|
|
@ -13,29 +13,31 @@ static const char *loglevels[] = {
|
||||||
|
|
||||||
static struct logger_properties logprops;
|
static struct logger_properties logprops;
|
||||||
|
|
||||||
void init_logger(FILE *__restrict__ dst, enum LOGLEVEL level){
|
void init_logger(FILE *dst, enum LOGLEVEL level) {
|
||||||
logprops.dst = dst;
|
logprops.dst = dst;
|
||||||
logprops.level = level;
|
logprops.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LOGLEVEL get_loglevel(const char *level){
|
enum LOGLEVEL get_loglevel(const char *level) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < NUM_LEVELS; i++){
|
for (i = 0; i < NUM_LEVELS; i++) {
|
||||||
if(!strcmp(level, loglevels[i])) return (enum LOGLEVEL) i;
|
if (!strcmp(level, loglevels[i])) {
|
||||||
|
return (enum LOGLEVEL) i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Could not understand log level %s\n", level);
|
fprintf(stderr, "Could not understand log level %s\n", level);
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void logprint(enum LOGLEVEL level, char *msg, ...){
|
void logprint(enum LOGLEVEL level, char *msg, ...) {
|
||||||
|
if (!logprops.dst) {
|
||||||
if(!logprops.dst){
|
|
||||||
fprintf(stderr, "Logger has been called, but was not initialized\n");
|
fprintf(stderr, "Logger has been called, but was not initialized\n");
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(level > logprops.level || level == QUIET) return ;
|
if (level > logprops.level || level == QUIET) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
char timestr[200];
|
char timestr[200];
|
||||||
|
@ -44,15 +46,12 @@ void logprint(enum LOGLEVEL level, char *msg, ...){
|
||||||
|
|
||||||
if (strftime(timestr, sizeof(timestr), "%Y/%m/%d %H:%M:%S", tmp) == 0) {
|
if (strftime(timestr, sizeof(timestr), "%Y/%m/%d %H:%M:%S", tmp) == 0) {
|
||||||
fprintf(stderr, "strftime returned 0");
|
fprintf(stderr, "strftime returned 0");
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(logprops.dst, "%s", timestr);
|
fprintf(logprops.dst, "%s", timestr);
|
||||||
|
|
||||||
fprintf(logprops.dst, " ");
|
fprintf(logprops.dst, " ");
|
||||||
|
|
||||||
fprintf(logprops.dst, "[%s]", loglevels[level]);
|
fprintf(logprops.dst, "[%s]", loglevels[level]);
|
||||||
|
|
||||||
fprintf(logprops.dst, " - ");
|
fprintf(logprops.dst, " - ");
|
||||||
|
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
|
@ -62,5 +61,4 @@ void logprint(enum LOGLEVEL level, char *msg, ...){
|
||||||
|
|
||||||
fprintf(logprops.dst, "\n");
|
fprintf(logprops.dst, "\n");
|
||||||
fflush(logprops.dst);
|
fflush(logprops.dst);
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,26 +14,23 @@ enum event_loop_fd {
|
||||||
|
|
||||||
static const char service_name[] = "org.freedesktop.impl.portal.desktop.wlr";
|
static const char service_name[] = "org.freedesktop.impl.portal.desktop.wlr";
|
||||||
|
|
||||||
int xdpw_usage(FILE* stream, int rc)
|
int xdpw_usage(FILE* stream, int rc) {
|
||||||
{
|
|
||||||
static const char* usage =
|
static const char* usage =
|
||||||
"Usage: xdg-desktop-portal-wlr [options]\n"
|
"Usage: xdg-desktop-portal-wlr [options]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -l, --loglevel=<loglevel> Select log level (default is ERROR).\n"
|
" -l, --loglevel=<loglevel> Select log level (default is ERROR).\n"
|
||||||
" QUIET, ERROR, WARN, INFO, DEBUG, TRACE\n"
|
" QUIET, ERROR, WARN, INFO, DEBUG, TRACE\n"
|
||||||
" -o, --output=<name> Select output to capture.\n"
|
" -o, --output=<name> Select output to capture.\n"
|
||||||
" -p,--pixelformat=BGRx|RGBx Force a pixelformat in pipewire\n"
|
" -p,--pixelformat=BGRx|RGBx Force a pixelformat in pipewire\n"
|
||||||
" metadata (performs no conversion).\n"
|
" metadata (performs no conversion).\n"
|
||||||
" -h,--help Get help (this text).\n"
|
" -h,--help Get help (this text).\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
fprintf(stream, "%s", usage);
|
fprintf(stream, "%s", usage);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
const char* output_name = NULL;
|
const char* output_name = NULL;
|
||||||
const char* forced_pixelformat = NULL;
|
const char* forced_pixelformat = NULL;
|
||||||
enum LOGLEVEL loglevel = ERROR;
|
enum LOGLEVEL loglevel = ERROR;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "pipewire_screencast.h"
|
#include "pipewire_screencast.h"
|
||||||
|
|
||||||
static inline void init_type(struct pwr_type *type, struct pw_type *map) {
|
static void init_type(struct pwr_type *type, struct pw_type *map) {
|
||||||
pw_type_get(map, SPA_TYPE__MediaType, &type->media_type);
|
pw_type_get(map, SPA_TYPE__MediaType, &type->media_type);
|
||||||
pw_type_get(map, SPA_TYPE__MediaSubtype, &type->media_subtype);
|
pw_type_get(map, SPA_TYPE__MediaSubtype, &type->media_subtype);
|
||||||
pw_type_get(map, SPA_TYPE_FORMAT__Video, &type->format_video);
|
pw_type_get(map, SPA_TYPE_FORMAT__Video, &type->format_video);
|
||||||
|
@ -9,8 +9,7 @@ static inline void init_type(struct pwr_type *type, struct pw_type *map) {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void writeFrameData(void *pwFramePointer, void *wlrFramePointer,
|
static void writeFrameData(void *pwFramePointer, void *wlrFramePointer,
|
||||||
uint32_t height, uint32_t stride, bool inverted) {
|
uint32_t height, uint32_t stride, bool inverted) {
|
||||||
|
|
||||||
if (!inverted) {
|
if (!inverted) {
|
||||||
memcpy(pwFramePointer, wlrFramePointer, height * stride);
|
memcpy(pwFramePointer, wlrFramePointer, height * stride);
|
||||||
return;
|
return;
|
||||||
|
@ -21,6 +20,7 @@ static void writeFrameData(void *pwFramePointer, void *wlrFramePointer,
|
||||||
void *pwRowPointer = pwFramePointer + (i * stride);
|
void *pwRowPointer = pwFramePointer + (i * stride);
|
||||||
memcpy(pwRowPointer, flippedWlrRowPointer, stride);
|
memcpy(pwRowPointer, flippedWlrRowPointer, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ static void pwr_on_event(void *data, uint64_t expirations) {
|
||||||
d[0].fd = -1;
|
d[0].fd = -1;
|
||||||
|
|
||||||
writeFrameData(d[0].data, ctx->simple_frame.data, ctx->simple_frame.height,
|
writeFrameData(d[0].data, ctx->simple_frame.data, ctx->simple_frame.height,
|
||||||
ctx->simple_frame.stride, ctx->simple_frame.y_invert);
|
ctx->simple_frame.stride, ctx->simple_frame.y_invert);
|
||||||
|
|
||||||
logprint(TRACE, "pipewire: pointer %p", d[0].data);
|
logprint(TRACE, "pipewire: pointer %p", d[0].data);
|
||||||
logprint(TRACE, "pipewire: size %d", d[0].maxsize);
|
logprint(TRACE, "pipewire: size %d", d[0].maxsize);
|
||||||
|
@ -76,17 +76,15 @@ static void pwr_on_event(void *data, uint64_t expirations) {
|
||||||
pw_stream_queue_buffer(ctx->stream, pw_buf);
|
pw_stream_queue_buffer(ctx->stream, pw_buf);
|
||||||
|
|
||||||
wlr_frame_free(state);
|
wlr_frame_free(state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwr_handle_stream_state_changed(void *data,
|
static void pwr_handle_stream_state_changed(void *data,
|
||||||
enum pw_stream_state old,
|
enum pw_stream_state old, enum pw_stream_state state, const char *error) {
|
||||||
enum pw_stream_state state,
|
|
||||||
const char *error) {
|
|
||||||
struct screencast_context *ctx = data;
|
struct screencast_context *ctx = data;
|
||||||
ctx->node_id = pw_stream_get_node_id(ctx->stream);
|
ctx->node_id = pw_stream_get_node_id(ctx->stream);
|
||||||
|
|
||||||
logprint(INFO, "pipewire: stream state changed to \"%s\"", pw_stream_state_as_string(state));
|
logprint(INFO, "pipewire: stream state changed to \"%s\"",
|
||||||
|
pw_stream_state_as_string(state));
|
||||||
logprint(INFO, "pipewire: node id is %d", ctx->node_id);
|
logprint(INFO, "pipewire: node id is %d", ctx->node_id);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
@ -100,45 +98,46 @@ static void pwr_handle_stream_state_changed(void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwr_handle_stream_format_changed(void *data,
|
static void pwr_handle_stream_format_changed(void *data,
|
||||||
const struct spa_pod *format) {
|
const struct spa_pod *format) {
|
||||||
struct screencast_context *ctx = data;
|
struct screencast_context *ctx = data;
|
||||||
struct pw_stream *stream = ctx->stream;
|
struct pw_stream *stream = ctx->stream;
|
||||||
struct pw_type *t = ctx->t;
|
struct pw_type *t = ctx->t;
|
||||||
uint8_t params_buffer[1024];
|
uint8_t params_buffer[1024];
|
||||||
struct spa_pod_builder b =
|
struct spa_pod_builder b =
|
||||||
SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
||||||
const struct spa_pod *params[2];
|
const struct spa_pod *params[2];
|
||||||
|
|
||||||
if (format == NULL) {
|
if (format == NULL) {
|
||||||
pw_stream_finish_format(stream, 0, NULL, 0);
|
pw_stream_finish_format(stream, 0, NULL, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spa_format_video_raw_parse(format, &ctx->pwr_format, &ctx->type.format_video);
|
spa_format_video_raw_parse(format, &ctx->pwr_format, &ctx->type.format_video);
|
||||||
|
|
||||||
params[0] = spa_pod_builder_object(
|
params[0] = spa_pod_builder_object(
|
||||||
&b, t->param.idBuffers, t->param_buffers.Buffers, ":",
|
&b, t->param.idBuffers, t->param_buffers.Buffers, ":",
|
||||||
t->param_buffers.size, "i", ctx->simple_frame.size, ":",
|
t->param_buffers.size, "i", ctx->simple_frame.size, ":",
|
||||||
t->param_buffers.stride, "i", ctx->simple_frame.stride, ":",
|
t->param_buffers.stride, "i", ctx->simple_frame.stride, ":",
|
||||||
t->param_buffers.buffers, "iru", BUFFERS, SPA_POD_PROP_MIN_MAX(1, 32),
|
t->param_buffers.buffers, "iru", BUFFERS, SPA_POD_PROP_MIN_MAX(1, 32),
|
||||||
":", t->param_buffers.align, "i", ALIGN);
|
":", t->param_buffers.align, "i", ALIGN);
|
||||||
|
|
||||||
params[1] = spa_pod_builder_object(&b, t->param.idMeta, t->param_meta.Meta,
|
params[1] = spa_pod_builder_object(&b,
|
||||||
":", t->param_meta.type, "I",
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
t->meta.Header, ":", t->param_meta.size,
|
":", t->param_meta.type, "I",
|
||||||
"i", sizeof(struct spa_meta_header));
|
t->meta.Header, ":", t->param_meta.size,
|
||||||
|
"i", sizeof(struct spa_meta_header));
|
||||||
|
|
||||||
pw_stream_finish_format(stream, 0, params, 2);
|
pw_stream_finish_format(stream, 0, params, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_stream_events pwr_stream_events = {
|
static const struct pw_stream_events pwr_stream_events = {
|
||||||
PW_VERSION_STREAM_EVENTS,
|
PW_VERSION_STREAM_EVENTS,
|
||||||
.state_changed = pwr_handle_stream_state_changed,
|
.state_changed = pwr_handle_stream_state_changed,
|
||||||
.format_changed = pwr_handle_stream_format_changed,
|
.format_changed = pwr_handle_stream_format_changed,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
||||||
enum pw_remote_state pwr_remote_state,
|
enum pw_remote_state pwr_remote_state, const char *error) {
|
||||||
const char *error) {
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
struct pw_remote *remote = ctx->remote;
|
struct pw_remote *remote = ctx->remote;
|
||||||
|
@ -146,7 +145,7 @@ static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
||||||
switch (pwr_remote_state) {
|
switch (pwr_remote_state) {
|
||||||
case PW_REMOTE_STATE_ERROR:
|
case PW_REMOTE_STATE_ERROR:
|
||||||
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
||||||
pw_remote_state_as_string(pwr_remote_state));
|
pw_remote_state_as_string(pwr_remote_state));
|
||||||
logprint(ERROR, "pipewire: remote error: %s", error);
|
logprint(ERROR, "pipewire: remote error: %s", error);
|
||||||
pw_loop_leave(state->pw_loop);
|
pw_loop_leave(state->pw_loop);
|
||||||
pw_loop_destroy(state->pw_loop);
|
pw_loop_destroy(state->pw_loop);
|
||||||
|
@ -159,47 +158,47 @@ static void pwr_handle_state_changed(void *data, enum pw_remote_state old,
|
||||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||||
|
|
||||||
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
||||||
pw_remote_state_as_string(pwr_remote_state));
|
pw_remote_state_as_string(pwr_remote_state));
|
||||||
|
|
||||||
ctx->stream = pw_stream_new(
|
ctx->stream = pw_stream_new(
|
||||||
remote, "wlr_screeencopy",
|
remote, "wlr_screeencopy",
|
||||||
pw_properties_new("media.class", "Video/Source", PW_NODE_PROP_MEDIA,
|
pw_properties_new("media.class",
|
||||||
"Video", PW_NODE_PROP_CATEGORY, "Source",
|
"Video/Source", PW_NODE_PROP_MEDIA,
|
||||||
PW_NODE_PROP_ROLE, "Screen", NULL));
|
"Video", PW_NODE_PROP_CATEGORY, "Source",
|
||||||
|
PW_NODE_PROP_ROLE, "Screen", NULL));
|
||||||
|
|
||||||
params[0] = spa_pod_builder_object(
|
params[0] = spa_pod_builder_object(
|
||||||
&b, ctx->t->param.idEnumFormat, ctx->t->spa_format, "I",
|
&b, ctx->t->param.idEnumFormat, ctx->t->spa_format, "I",
|
||||||
ctx->type.media_type.video, "I", ctx->type.media_subtype.raw, ":",
|
ctx->type.media_type.video, "I", ctx->type.media_subtype.raw, ":",
|
||||||
ctx->type.format_video.format, "I", pipewire_from_wl_shm(ctx), ":",
|
ctx->type.format_video.format, "I", pipewire_from_wl_shm(ctx), ":",
|
||||||
ctx->type.format_video.size, "Rru",
|
ctx->type.format_video.size, "Rru",
|
||||||
&SPA_RECTANGLE(ctx->simple_frame.width, ctx->simple_frame.height),
|
&SPA_RECTANGLE(ctx->simple_frame.width, ctx->simple_frame.height),
|
||||||
SPA_POD_PROP_MIN_MAX(&SPA_RECTANGLE(1, 1), &SPA_RECTANGLE(4096, 4096)),
|
SPA_POD_PROP_MIN_MAX(&SPA_RECTANGLE(1, 1), &SPA_RECTANGLE(4096, 4096)),
|
||||||
":", ctx->type.format_video.framerate, "F",
|
":", ctx->type.format_video.framerate, "F",
|
||||||
// specify variable framerate
|
// specify variable framerate
|
||||||
&SPA_FRACTION(0, 1),
|
&SPA_FRACTION(0, 1),
|
||||||
":", ctx->type.format_video.max_framerate, "F",
|
":", ctx->type.format_video.max_framerate, "F",
|
||||||
// with a maximum at the wlroots specified hardware framerate
|
// with a maximum at the wlroots specified hardware framerate
|
||||||
&SPA_FRACTION(ctx->framerate, 1));
|
&SPA_FRACTION(ctx->framerate, 1));
|
||||||
|
|
||||||
pw_stream_add_listener(ctx->stream, &ctx->stream_listener,
|
pw_stream_add_listener(ctx->stream, &ctx->stream_listener,
|
||||||
&pwr_stream_events, ctx);
|
&pwr_stream_events, ctx);
|
||||||
|
|
||||||
pw_stream_connect(ctx->stream, PW_DIRECTION_OUTPUT, NULL,
|
pw_stream_connect(ctx->stream, PW_DIRECTION_OUTPUT, NULL,
|
||||||
PW_STREAM_FLAG_DRIVER | PW_STREAM_FLAG_MAP_BUFFERS,
|
PW_STREAM_FLAG_DRIVER | PW_STREAM_FLAG_MAP_BUFFERS, params, 1);
|
||||||
params, 1);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
logprint(INFO, "pipewire: remote state changed to \"%s\"",
|
||||||
pw_remote_state_as_string(pwr_remote_state));
|
pw_remote_state_as_string(pwr_remote_state));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_remote_events pwr_remote_events = {
|
static const struct pw_remote_events pwr_remote_events = {
|
||||||
PW_VERSION_REMOTE_EVENTS,
|
PW_VERSION_REMOTE_EVENTS,
|
||||||
.state_changed = pwr_handle_state_changed,
|
.state_changed = pwr_handle_state_changed,
|
||||||
};
|
};
|
||||||
|
|
||||||
void *pwr_start(struct xdpw_state *state) {
|
void *pwr_start(struct xdpw_state *state) {
|
||||||
|
@ -216,10 +215,10 @@ void *pwr_start(struct xdpw_state *state) {
|
||||||
|
|
||||||
/* make an event to signal frame ready */
|
/* make an event to signal frame ready */
|
||||||
ctx->event =
|
ctx->event =
|
||||||
pw_loop_add_event(state->pw_loop, pwr_on_event, state);
|
pw_loop_add_event(state->pw_loop, pwr_on_event, state);
|
||||||
|
|
||||||
pw_remote_add_listener(ctx->remote, &ctx->remote_listener, &pwr_remote_events,
|
pw_remote_add_listener(ctx->remote, &ctx->remote_listener, &pwr_remote_events,
|
||||||
state);
|
state);
|
||||||
pw_remote_connect(ctx->remote);
|
pw_remote_connect(ctx->remote);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -9,8 +9,8 @@ int setup_outputs(struct xdpw_state *state) {
|
||||||
|
|
||||||
struct wayland_output *output, *tmp_o;
|
struct wayland_output *output, *tmp_o;
|
||||||
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
wl_list_for_each_reverse_safe(output, tmp_o, &ctx->output_list, link) {
|
||||||
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s", output->make,
|
logprint(INFO, "wlroots: capturable output: %s model: %s: id: %i name: %s",
|
||||||
output->model, output->id, output->name);
|
output->make, output->model, output->id, output->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wayland_output *out;
|
struct wayland_output *out;
|
||||||
|
@ -18,13 +18,13 @@ int setup_outputs(struct xdpw_state *state) {
|
||||||
out = wlr_output_find_by_name(&ctx->output_list, ctx->output_name);
|
out = wlr_output_find_by_name(&ctx->output_list, ctx->output_name);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
logprint(ERROR, "wlroots: no such output");
|
logprint(ERROR, "wlroots: no such output");
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out = wlr_output_first(&ctx->output_list);
|
out = wlr_output_first(&ctx->output_list);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
logprint(ERROR, "wlroots: no output found");
|
logprint(ERROR, "wlroots: no output found");
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +39,10 @@ int setup_outputs(struct xdpw_state *state) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *start_screencast(void *data){
|
void *start_screencast(void *data) {
|
||||||
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
wlr_register_cb(state);
|
wlr_register_cb(state);
|
||||||
|
|
||||||
// process at least one frame so that we know
|
// process at least one frame so that we know
|
||||||
// some of the metadata required for the pipewire
|
// some of the metadata required for the pipewire
|
||||||
// remote state connected event
|
// remote state connected event
|
||||||
|
@ -54,7 +52,6 @@ void *start_screencast(void *data){
|
||||||
pwr_start(state);
|
pwr_start(state);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
|
@ -80,13 +77,13 @@ static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
|
|
||||||
char* key;
|
char* key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
while((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(key, "session_handle_token") == 0) {
|
if (strcmp(key, "session_handle_token") == 0) {
|
||||||
char* token;
|
char* token;
|
||||||
sd_bus_message_read(msg, "v", "s", &token);
|
sd_bus_message_read(msg, "v", "s", &token);
|
||||||
logprint(INFO, "dbus: option token: %s", token);
|
logprint(INFO, "dbus: option token: %s", token);
|
||||||
|
@ -142,8 +139,8 @@ static int method_screencast_create_session(sd_bus_message *msg, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
static int method_screencast_select_sources(sd_bus_message *msg, void *data,
|
||||||
|
sd_bus_error *ret_error) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -168,20 +165,20 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_
|
||||||
|
|
||||||
char* key;
|
char* key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
while((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(key, "multiple") == 0) {
|
if (strcmp(key, "multiple") == 0) {
|
||||||
bool multiple;
|
bool multiple;
|
||||||
sd_bus_message_read(msg, "v", "b", &multiple);
|
sd_bus_message_read(msg, "v", "b", &multiple);
|
||||||
logprint(INFO, "dbus: option multiple: %x", multiple);
|
logprint(INFO, "dbus: option multiple: %x", multiple);
|
||||||
} else if(strcmp(key, "types") == 0) {
|
} else if (strcmp(key, "types") == 0) {
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
sd_bus_message_read(msg, "v", "u", &mask);
|
sd_bus_message_read(msg, "v", "u", &mask);
|
||||||
logprint(INFO, "dbus: option types: %x", mask);
|
logprint(INFO, "dbus: option types:%x", mask);
|
||||||
} else {
|
} else {
|
||||||
logprint(WARN, "dbus: unknown option %s", key);
|
logprint(WARN, "dbus: unknown option %s", key);
|
||||||
sd_bus_message_skip(msg, "v");
|
sd_bus_message_skip(msg, "v");
|
||||||
|
@ -219,8 +216,8 @@ static int method_screencast_select_sources(sd_bus_message *msg, void *data, sd_
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
static int method_screencast_start(sd_bus_message *msg, void *data,
|
||||||
|
sd_bus_error *ret_error) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
@ -247,7 +244,7 @@ static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error
|
||||||
|
|
||||||
char* key;
|
char* key;
|
||||||
int innerRet = 0;
|
int innerRet = 0;
|
||||||
while((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||||
if (innerRet < 0) {
|
if (innerRet < 0) {
|
||||||
return innerRet;
|
return innerRet;
|
||||||
|
@ -275,19 +272,19 @@ static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(ctx->node_id == 0){
|
while (ctx->node_id == 0) {
|
||||||
int ret = pw_loop_iterate(state->pw_loop, 0);
|
int ret = pw_loop_iterate(state->pw_loop, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
logprint(ERROR, "pipewire_loop_iterate failed: %s",
|
logprint(ERROR, "pipewire_loop_iterate failed: %s", spa_strerror(ret));
|
||||||
spa_strerror(ret));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
ret = sd_bus_message_append(reply, "ua{sv}", PORTAL_RESPONSE_SUCCESS, 1,
|
||||||
"streams", "a(ua{sv})", 1,
|
"streams", "a(ua{sv})", 1,
|
||||||
ctx->node_id, 2,
|
ctx->node_id, 2,
|
||||||
"position", "(ii)", 0, 0,
|
"position", "(ii)", 0, 0,
|
||||||
"size", "(ii)", ctx->simple_frame.width, ctx->simple_frame.height);
|
"size", "(ii)", ctx->simple_frame.width, ctx->simple_frame.height);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -303,9 +300,12 @@ static int method_screencast_start(sd_bus_message *msg, void *data, sd_bus_error
|
||||||
|
|
||||||
static const sd_bus_vtable screencast_vtable[] = {
|
static const sd_bus_vtable screencast_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}", method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}",
|
||||||
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}", method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
method_screencast_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}", method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("SelectSources", "oosa{sv}", "ua{sv}",
|
||||||
|
method_screencast_select_sources, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD("Start", "oossa{sv}", "ua{sv}",
|
||||||
|
method_screencast_start, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -316,11 +316,10 @@ int init_screencast(struct xdpw_state *state, const char *output_name, const cha
|
||||||
state->screencast = (struct screencast_context) { 0 };
|
state->screencast = (struct screencast_context) { 0 };
|
||||||
state->screencast.forced_pixelformat = forced_pixelformat;
|
state->screencast.forced_pixelformat = forced_pixelformat;
|
||||||
state->screencast.output_name = output_name;
|
state->screencast.output_name = output_name;
|
||||||
state->screencast.simple_frame = (struct simple_frame){0};
|
state->screencast.simple_frame = (struct simple_frame) { 0 };
|
||||||
state->screencast.simple_frame.damage = &(struct damage){0};
|
state->screencast.simple_frame.damage = &(struct damage) { 0 };
|
||||||
|
|
||||||
int err;
|
int err = wlr_screencopy_init(state);
|
||||||
err = wlr_screencopy_init(state);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -328,7 +327,7 @@ int init_screencast(struct xdpw_state *state, const char *output_name, const cha
|
||||||
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
return sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name,
|
||||||
screencast_vtable, state);
|
screencast_vtable, state);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
wlr_screencopy_uninit(&state->screencast);
|
wlr_screencopy_uninit(&state->screencast);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,37 @@
|
||||||
#include "screencast_common.h"
|
#include "screencast_common.h"
|
||||||
|
|
||||||
char *strdup(const char *src) {
|
|
||||||
char *dst = malloc(strlen(src) + 1); // Space for length plus nul
|
|
||||||
if (dst == NULL)
|
|
||||||
return NULL; // No memory
|
|
||||||
strcpy(dst, src); // Copy the characters
|
|
||||||
return dst; // Return the new string
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pipewire_from_wl_shm(void *data) {
|
uint32_t pipewire_from_wl_shm(void *data) {
|
||||||
struct screencast_context *ctx = data;
|
struct screencast_context *ctx = data;
|
||||||
|
|
||||||
if(ctx->forced_pixelformat){
|
if (ctx->forced_pixelformat) {
|
||||||
if(strcmp(ctx->forced_pixelformat, "BGRx") == 0) {
|
if (strcmp(ctx->forced_pixelformat, "BGRx") == 0) {
|
||||||
return ctx->type.video_format.BGRx;
|
return ctx->type.video_format.BGRx;
|
||||||
}
|
}
|
||||||
if(strcmp(ctx->forced_pixelformat, "RGBx") == 0){
|
if (strcmp(ctx->forced_pixelformat, "RGBx") == 0) {
|
||||||
return ctx->type.video_format.RGBx;
|
return ctx->type.video_format.RGBx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ctx->simple_frame.format) {
|
switch (ctx->simple_frame.format) {
|
||||||
case WL_SHM_FORMAT_ARGB8888:
|
case WL_SHM_FORMAT_ARGB8888:
|
||||||
return ctx->type.video_format.BGRA;
|
return ctx->type.video_format.BGRA;
|
||||||
case WL_SHM_FORMAT_XRGB8888:
|
case WL_SHM_FORMAT_XRGB8888:
|
||||||
return ctx->type.video_format.BGRx;
|
return ctx->type.video_format.BGRx;
|
||||||
case WL_SHM_FORMAT_RGBA8888:
|
case WL_SHM_FORMAT_RGBA8888:
|
||||||
return ctx->type.video_format.ABGR;
|
return ctx->type.video_format.ABGR;
|
||||||
case WL_SHM_FORMAT_RGBX8888:
|
case WL_SHM_FORMAT_RGBX8888:
|
||||||
return ctx->type.video_format.xBGR;
|
return ctx->type.video_format.xBGR;
|
||||||
case WL_SHM_FORMAT_ABGR8888:
|
case WL_SHM_FORMAT_ABGR8888:
|
||||||
return ctx->type.video_format.RGBA;
|
return ctx->type.video_format.RGBA;
|
||||||
case WL_SHM_FORMAT_XBGR8888:
|
case WL_SHM_FORMAT_XBGR8888:
|
||||||
return ctx->type.video_format.RGBx;
|
return ctx->type.video_format.RGBx;
|
||||||
case WL_SHM_FORMAT_BGRA8888:
|
case WL_SHM_FORMAT_BGRA8888:
|
||||||
return ctx->type.video_format.ARGB;
|
return ctx->type.video_format.ARGB;
|
||||||
case WL_SHM_FORMAT_BGRX8888:
|
case WL_SHM_FORMAT_BGRX8888:
|
||||||
return ctx->type.video_format.xRGB;
|
return ctx->type.video_format.xRGB;
|
||||||
case WL_SHM_FORMAT_NV12:
|
case WL_SHM_FORMAT_NV12:
|
||||||
return ctx->type.video_format.NV12;
|
return ctx->type.video_format.NV12;
|
||||||
default:
|
default:
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
#include "wlr_screencast.h"
|
#include "wlr_screencast.h"
|
||||||
#include "xdpw.h"
|
#include "xdpw.h"
|
||||||
|
|
||||||
void wlr_frame_free(struct xdpw_state *state) {
|
void wlr_frame_free(struct xdpw_state *state) {
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_destroy(state->screencast.wlr_frame);
|
zwlr_screencopy_frame_v1_destroy(state->screencast.wlr_frame);
|
||||||
munmap(state->screencast.simple_frame.data, state->screencast.simple_frame.size);
|
munmap(state->screencast.simple_frame.data, state->screencast.simple_frame.size);
|
||||||
wl_buffer_destroy(state->screencast.simple_frame.buffer);
|
wl_buffer_destroy(state->screencast.simple_frame.buffer);
|
||||||
logprint(TRACE, "wlroots: frame destroyed");
|
logprint(TRACE, "wlroots: frame destroyed");
|
||||||
|
|
||||||
if(!state->screencast.quit && !state->screencast.err){
|
if (!state->screencast.quit && !state->screencast.err) {
|
||||||
wlr_register_cb(state);
|
wlr_register_cb(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
||||||
enum wl_shm_format fmt, int width,
|
enum wl_shm_format fmt, int width, int height, int stride,
|
||||||
int height, int stride,
|
void **data_out) {
|
||||||
void **data_out) {
|
|
||||||
int size = stride * height;
|
int size = stride * height;
|
||||||
|
|
||||||
const char shm_name[] = "/wlroots-screencopy";
|
const char shm_name[] = "/wlroots-screencopy";
|
||||||
|
@ -47,7 +46,7 @@ static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
||||||
struct wl_shm_pool *pool = wl_shm_create_pool(ctx->shm, fd, size);
|
struct wl_shm_pool *pool = wl_shm_create_pool(ctx->shm, fd, size);
|
||||||
close(fd);
|
close(fd);
|
||||||
struct wl_buffer *buffer =
|
struct wl_buffer *buffer =
|
||||||
wl_shm_pool_create_buffer(pool, 0, width, height, stride, fmt);
|
wl_shm_pool_create_buffer(pool, 0, width, height, stride, fmt);
|
||||||
wl_shm_pool_destroy(pool);
|
wl_shm_pool_destroy(pool);
|
||||||
|
|
||||||
*data_out = data;
|
*data_out = data;
|
||||||
|
@ -55,8 +54,7 @@ static struct wl_buffer *create_shm_buffer(struct screencast_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t format, uint32_t width, uint32_t height,
|
uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
|
||||||
uint32_t stride) {
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
@ -68,10 +66,11 @@ static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
ctx->simple_frame.size = stride * height;
|
ctx->simple_frame.size = stride * height;
|
||||||
ctx->simple_frame.format = format;
|
ctx->simple_frame.format = format;
|
||||||
ctx->simple_frame.buffer = create_shm_buffer(ctx, format, width, height,
|
ctx->simple_frame.buffer = create_shm_buffer(ctx, format, width, height,
|
||||||
stride, &ctx->simple_frame.data);
|
stride, &ctx->simple_frame.data);
|
||||||
|
|
||||||
if (ctx->simple_frame.buffer == NULL) {
|
if (ctx->simple_frame.buffer == NULL) {
|
||||||
logprint(ERROR, "wlroots: failed to create buffer");
|
logprint(ERROR, "wlroots: failed to create buffer");
|
||||||
exit(EXIT_FAILURE);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_copy_with_damage(frame, ctx->simple_frame.buffer);
|
zwlr_screencopy_frame_v1_copy_with_damage(frame, ctx->simple_frame.buffer);
|
||||||
|
@ -79,18 +78,16 @@ static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: flags event handler");
|
logprint(TRACE, "wlroots: flags event handler");
|
||||||
ctx->simple_frame.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
ctx->simple_frame.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo,
|
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||||
uint32_t tv_nsec) {
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
@ -105,11 +102,10 @@ static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_frame_free(state);
|
wlr_frame_free(state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_failed(void *data,
|
static void wlr_frame_failed(void *data,
|
||||||
struct zwlr_screencopy_frame_v1 *frame) {
|
struct zwlr_screencopy_frame_v1 *frame) {
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
@ -120,8 +116,7 @@ static void wlr_frame_failed(void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
uint32_t x, uint32_t y, uint32_t width,
|
uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
||||||
uint32_t height) {
|
|
||||||
struct xdpw_state *state = data;
|
struct xdpw_state *state = data;
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
|
@ -134,38 +129,34 @@ static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
||||||
.buffer = wlr_frame_buffer,
|
.buffer = wlr_frame_buffer,
|
||||||
.flags = wlr_frame_flags,
|
.flags = wlr_frame_flags,
|
||||||
.ready = wlr_frame_ready,
|
.ready = wlr_frame_ready,
|
||||||
.failed = wlr_frame_failed,
|
.failed = wlr_frame_failed,
|
||||||
.damage = wlr_frame_damage,
|
.damage = wlr_frame_damage,
|
||||||
};
|
};
|
||||||
|
|
||||||
void wlr_register_cb(struct xdpw_state *state) {
|
void wlr_register_cb(struct xdpw_state *state) {
|
||||||
|
|
||||||
struct screencast_context *ctx = &state->screencast;
|
struct screencast_context *ctx = &state->screencast;
|
||||||
|
|
||||||
ctx->frame_callback = zwlr_screencopy_manager_v1_capture_output(
|
ctx->frame_callback = zwlr_screencopy_manager_v1_capture_output(
|
||||||
ctx->screencopy_manager, ctx->with_cursor, ctx->target_output->output);
|
ctx->screencopy_manager, ctx->with_cursor, ctx->target_output->output);
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_add_listener(ctx->frame_callback,
|
zwlr_screencopy_frame_v1_add_listener(ctx->frame_callback,
|
||||||
&wlr_frame_listener, state);
|
&wlr_frame_listener, state);
|
||||||
logprint(TRACE, "wlroots: callbacks registered");
|
logprint(TRACE, "wlroots: callbacks registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_geometry(void *data, struct wl_output *wl_output,
|
static void wlr_output_handle_geometry(void *data, struct wl_output *wl_output,
|
||||||
int32_t x, int32_t y, int32_t phys_width,
|
int32_t x, int32_t y, int32_t phys_width, int32_t phys_height,
|
||||||
int32_t phys_height, int32_t subpixel,
|
int32_t subpixel, const char *make, const char *model, int32_t transform) {
|
||||||
const char *make, const char *model,
|
|
||||||
int32_t transform) {
|
|
||||||
struct wayland_output *output = data;
|
struct wayland_output *output = data;
|
||||||
output->make = strdup(make);
|
output->make = strdup(make);
|
||||||
output->model = strdup(model);
|
output->model = strdup(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
|
static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
|
||||||
uint32_t flags, int32_t width,
|
uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||||
int32_t height, int32_t refresh) {
|
|
||||||
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
||||||
struct wayland_output *output = data;
|
struct wayland_output *output = data;
|
||||||
output->framerate = (float)refresh/1000;
|
output->framerate = (float)refresh/1000;
|
||||||
|
@ -177,49 +168,49 @@ static void wlr_output_handle_done(void *data, struct wl_output *wl_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_scale(void *data, struct wl_output *wl_output,
|
static void wlr_output_handle_scale(void *data, struct wl_output *wl_output,
|
||||||
int32_t factor) {
|
int32_t factor) {
|
||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_output_listener wlr_output_listener = {
|
static const struct wl_output_listener wlr_output_listener = {
|
||||||
.geometry = wlr_output_handle_geometry,
|
.geometry = wlr_output_handle_geometry,
|
||||||
.mode = wlr_output_handle_mode,
|
.mode = wlr_output_handle_mode,
|
||||||
.done = wlr_output_handle_done,
|
.done = wlr_output_handle_done,
|
||||||
.scale = wlr_output_handle_scale,
|
.scale = wlr_output_handle_scale,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wlr_xdg_output_name(void* data, struct zxdg_output_v1* xdg_output,
|
static void wlr_xdg_output_name(void* data, struct zxdg_output_v1* xdg_output,
|
||||||
const char* name){
|
const char* name) {
|
||||||
struct wayland_output *output = data;
|
struct wayland_output *output = data;
|
||||||
|
|
||||||
output->name = strdup(name);
|
output->name = strdup(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dontcare(){
|
static void noop() {
|
||||||
|
// This space intentionally left blank
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct zxdg_output_v1_listener wlr_xdg_output_listener = {
|
static const struct zxdg_output_v1_listener wlr_xdg_output_listener = {
|
||||||
.logical_position = dontcare,
|
.logical_position = noop,
|
||||||
.logical_size = dontcare,
|
.logical_size = noop,
|
||||||
.done = NULL, /* Deprecated */
|
.done = NULL, /* Deprecated */
|
||||||
.description = dontcare,
|
.description = noop,
|
||||||
.name = wlr_xdg_output_name,
|
.name = wlr_xdg_output_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
void wlr_add_xdg_output_listener(struct wayland_output *output,
|
void wlr_add_xdg_output_listener(struct wayland_output *output,
|
||||||
struct zxdg_output_v1* xdg_output){
|
struct zxdg_output_v1* xdg_output) {
|
||||||
output->xdg_output = xdg_output;
|
output->xdg_output = xdg_output;
|
||||||
zxdg_output_v1_add_listener(output->xdg_output, &wlr_xdg_output_listener,
|
zxdg_output_v1_add_listener(output->xdg_output, &wlr_xdg_output_listener,
|
||||||
output);
|
output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_init_xdg_outputs(struct screencast_context *ctx){
|
static void wlr_init_xdg_outputs(struct screencast_context *ctx) {
|
||||||
struct wayland_output *output, *tmp;
|
struct wayland_output *output, *tmp;
|
||||||
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
||||||
struct zxdg_output_v1 *xdg_output =
|
struct zxdg_output_v1 *xdg_output =
|
||||||
zxdg_output_manager_v1_get_xdg_output(
|
zxdg_output_manager_v1_get_xdg_output( ctx->xdg_output_manager,
|
||||||
ctx->xdg_output_manager, output->output);
|
output->output);
|
||||||
|
|
||||||
wlr_add_xdg_output_listener(output, xdg_output);
|
wlr_add_xdg_output_listener(output, xdg_output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,19 +223,19 @@ struct wayland_output *wlr_output_first(struct wl_list *output_list) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wayland_output *wlr_output_find_by_name(struct wl_list *output_list, const char* name) {
|
struct wayland_output *wlr_output_find_by_name(struct wl_list *output_list,
|
||||||
|
const char* name) {
|
||||||
struct wayland_output *output, *tmp;
|
struct wayland_output *output, *tmp;
|
||||||
wl_list_for_each_safe(output, tmp, output_list, link){
|
wl_list_for_each_safe(output, tmp, output_list, link) {
|
||||||
if (strcmp(output->name, name) == 0){
|
if (strcmp(output->name, name) == 0) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct wayland_output *wlr_output_find(struct screencast_context *ctx,
|
struct wayland_output *wlr_output_find(struct screencast_context *ctx,
|
||||||
struct wl_output *out, uint32_t id) {
|
struct wl_output *out, uint32_t id) {
|
||||||
struct wayland_output *output, *tmp;
|
struct wayland_output *output, *tmp;
|
||||||
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
||||||
if ((output->output == out) || (output->id == id)) {
|
if ((output->output == out) || (output->id == id)) {
|
||||||
|
@ -259,8 +250,7 @@ static void wlr_remove_output(struct wayland_output *out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
||||||
uint32_t id, const char *interface,
|
uint32_t id, const char *interface, uint32_t ver) {
|
||||||
uint32_t ver) {
|
|
||||||
struct screencast_context *ctx = data;
|
struct screencast_context *ctx = data;
|
||||||
|
|
||||||
if (!strcmp(interface, wl_output_interface.name)) {
|
if (!strcmp(interface, wl_output_interface.name)) {
|
||||||
|
@ -275,7 +265,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
||||||
|
|
||||||
if (!strcmp(interface, zwlr_screencopy_manager_v1_interface.name)) {
|
if (!strcmp(interface, zwlr_screencopy_manager_v1_interface.name)) {
|
||||||
ctx->screencopy_manager = wl_registry_bind(
|
ctx->screencopy_manager = wl_registry_bind(
|
||||||
reg, id, &zwlr_screencopy_manager_v1_interface, SC_MANAGER_VERSION);
|
reg, id, &zwlr_screencopy_manager_v1_interface, SC_MANAGER_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(interface, wl_shm_interface.name) == 0) {
|
if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||||
|
@ -289,14 +279,14 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_registry_handle_remove(void *data, struct wl_registry *reg,
|
static void wlr_registry_handle_remove(void *data, struct wl_registry *reg,
|
||||||
uint32_t id) {
|
uint32_t id) {
|
||||||
wlr_remove_output(
|
wlr_remove_output(
|
||||||
wlr_output_find((struct screencast_context *)data, NULL, id));
|
wlr_output_find((struct screencast_context *)data, NULL, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_registry_listener wlr_registry_listener = {
|
static const struct wl_registry_listener wlr_registry_listener = {
|
||||||
.global = wlr_registry_handle_add,
|
.global = wlr_registry_handle_add,
|
||||||
.global_remove = wlr_registry_handle_remove,
|
.global_remove = wlr_registry_handle_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
int wlr_screencopy_init(struct xdpw_state *state) {
|
int wlr_screencopy_init(struct xdpw_state *state) {
|
||||||
|
@ -330,7 +320,7 @@ int wlr_screencopy_init(struct xdpw_state *state) {
|
||||||
// make sure our wlroots supports screencopy protocol
|
// make sure our wlroots supports screencopy protocol
|
||||||
if (!ctx->screencopy_manager) {
|
if (!ctx->screencopy_manager) {
|
||||||
logprint(ERROR, "Compositor doesn't support %s!",
|
logprint(ERROR, "Compositor doesn't support %s!",
|
||||||
zwlr_screencopy_manager_v1_interface.name);
|
zwlr_screencopy_manager_v1_interface.name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue