protocols: expose output-management, honor resizes standalone
Advertise zwlr_output_manager_v1 with the single head, published on setup and re-published from the commit path whenever the size lands (resizes apply lazily, so the commit -- not the request -- is where the new size becomes observable). Client sizes apply standalone through the normal resize path (tabs reflow, swapchain follows); nested refuses anything but the live size since the host owns the geometry. Disabling, scale and transform changes are refused; superseded configs are destroyed after feedback. Standalone output_resize now owns the canvas size so client resizes reach the lazy modeset. wltest gains --output-mgmt; smoke tests cover the global, head listing, and an 800x600 apply with tab reflow.
This commit is contained in:
parent
fcd3bca53b
commit
d8164ce315
6 changed files with 1158 additions and 3 deletions
|
|
@ -422,6 +422,15 @@ artwork shows where clients provide it. The guesser stays as the fallback
|
||||||
icon: clearing the icon drops back to guessing, and windows that never
|
icon: clearing the icon drops back to guessing, and windows that never
|
||||||
set one behave exactly as before.
|
set one behave exactly as before.
|
||||||
|
|
||||||
|
## Output management (`wlr-output-management`)
|
||||||
|
|
||||||
|
Kick advertises `zwlr_output_manager_v1`, so display tools (kanshi,
|
||||||
|
wdisplays) can list the single head and request sizes. Standalone honors
|
||||||
|
custom sizes through the normal resize path (tabs reflow, clients learn
|
||||||
|
the new size); nested refuses anything but the live size, because the
|
||||||
|
host window owns the geometry there. Disabling, scale and transform
|
||||||
|
changes are refused everywhere: one fixed output per session.
|
||||||
|
|
||||||
## Logging (`KICK_LOG`)
|
## Logging (`KICK_LOG`)
|
||||||
|
|
||||||
Quiet by default: a plain launch prints nothing to the launching terminal
|
Quiet by default: a plain launch prints nothing to the launching terminal
|
||||||
|
|
|
||||||
171
kick.c
171
kick.c
|
|
@ -96,6 +96,7 @@
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output_power_management_v1.h>
|
#include <wlr/types/wlr_output_power_management_v1.h>
|
||||||
|
#include <wlr/types/wlr_output_management_v1.h>
|
||||||
#include <wlr/types/wlr_pointer.h>
|
#include <wlr/types/wlr_pointer.h>
|
||||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||||
#include <wlr/types/wlr_pointer_gestures_v1.h>
|
#include <wlr/types/wlr_pointer_gestures_v1.h>
|
||||||
|
|
@ -393,6 +394,13 @@ struct kick_server {
|
||||||
struct wlr_output_power_manager_v1 *output_power_mgr;
|
struct wlr_output_power_manager_v1 *output_power_mgr;
|
||||||
struct wl_listener output_power_set_mode;
|
struct wl_listener output_power_set_mode;
|
||||||
bool output_powered;
|
bool output_powered;
|
||||||
|
/* Output management (kanshi/wdisplays reconfigure the output): the
|
||||||
|
single server output is published as a head; client size requests
|
||||||
|
are honored standalone and refused nested (the host owns the size).
|
||||||
|
Scale/transform changes and disabling are unsupported. */
|
||||||
|
struct wlr_output_manager_v1 *output_mgr;
|
||||||
|
struct wl_listener output_mgr_apply;
|
||||||
|
struct wl_listener output_mgr_test;
|
||||||
/* Gamma control (night-light tools like wlsunset/gammastep): a client
|
/* Gamma control (night-light tools like wlsunset/gammastep): a client
|
||||||
sets a per-output ramp; wlroots rejects outputs with no LUT (e.g.
|
sets a per-output ramp; wlroots rejects outputs with no LUT (e.g.
|
||||||
the headless output) itself, so the handler only commits ramps for
|
the headless output) itself, so the handler only commits ramps for
|
||||||
|
|
@ -870,6 +878,9 @@ static const char *foreign_str(const char *s);
|
||||||
static struct kick_window *tab_current_window(struct kick_tab *tab);
|
static struct kick_window *tab_current_window(struct kick_tab *tab);
|
||||||
/* Toplevel-icon body lives with the overlay code; called from teardown. */
|
/* Toplevel-icon body lives with the overlay code; called from teardown. */
|
||||||
static void icon_proto_release(struct kick_window *w);
|
static void icon_proto_release(struct kick_window *w);
|
||||||
|
/* Output-management publish lives with the modeset handlers; called from
|
||||||
|
output setup and every resize. */
|
||||||
|
static void output_mgmt_publish(void);
|
||||||
static struct kick_tab *pick_successor(struct kick_tab *tab,
|
static struct kick_tab *pick_successor(struct kick_tab *tab,
|
||||||
bool prefer_right);
|
bool prefer_right);
|
||||||
static void remove_tab(struct kick_tab *tab);
|
static void remove_tab(struct kick_tab *tab);
|
||||||
|
|
@ -2479,6 +2490,15 @@ static void output_resize(int width, int height) {
|
||||||
if (height < 50) height = 50;
|
if (height < 50) height = 50;
|
||||||
if (!server.output || !server.allocator) return;
|
if (!server.output || !server.allocator) return;
|
||||||
|
|
||||||
|
/* Standalone has no host window tracking the size: the canvas follows
|
||||||
|
the request so the lazy modeset in apply_pending_output_resize
|
||||||
|
picks it up at render (nested is a no-op: the args already are the
|
||||||
|
host window's size). */
|
||||||
|
if (server.standalone) {
|
||||||
|
host.width = width;
|
||||||
|
host.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
/* The new size is applied to the output lazily at render time (see
|
/* The new size is applied to the output lazily at render time (see
|
||||||
apply_pending_output_resize); here only the scene geometry and the
|
apply_pending_output_resize); here only the scene geometry and the
|
||||||
clients are told, so configure-time stays free of modesets and
|
clients are told, so configure-time stays free of modesets and
|
||||||
|
|
@ -2706,6 +2726,10 @@ server.output = output;
|
||||||
server.overlay_damage_rect = wlr_scene_rect_create(
|
server.overlay_damage_rect = wlr_scene_rect_create(
|
||||||
&server.scene->tree, w, h, (float[]){ 0.0f, 0.0f, 0.0f, 0.0f });
|
&server.scene->tree, w, h, (float[]){ 0.0f, 0.0f, 0.0f, 0.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Publish the fresh output to management clients (kanshi/wdisplays
|
||||||
|
learn the head and its modes/size on bind). */
|
||||||
|
output_mgmt_publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nearest live tab, scanning right first (prefer_right) or left first.
|
/* Nearest live tab, scanning right first (prefer_right) or left first.
|
||||||
|
|
@ -6193,6 +6217,141 @@ static void handle_output_power_set_mode(struct wl_listener *listener,
|
||||||
kick_request_redraw();
|
kick_request_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===================== Output management =====================
|
||||||
|
kanshi/wdisplays-style clients list the single head and request sizes.
|
||||||
|
Standalone honors custom sizes through the normal resize path (tabs
|
||||||
|
reflow, swapchain follows lazily at render); nested refuses anything
|
||||||
|
but the live size because the host window owns the geometry. Anything
|
||||||
|
beyond size (disabling, scale, transform) is refused everywhere: one
|
||||||
|
fixed output per session. Successful applies republish so listening
|
||||||
|
clients converge. */
|
||||||
|
|
||||||
|
/* Broadcast the live output as the manager's current configuration;
|
||||||
|
wlroots creates/updates/destroys heads from it and only notifies on
|
||||||
|
change. No-op until both manager and output exist. */
|
||||||
|
static void output_mgmt_publish(void) {
|
||||||
|
if (!server.output_mgr || !server.output)
|
||||||
|
return;
|
||||||
|
struct wlr_output_configuration_v1 *config =
|
||||||
|
wlr_output_configuration_v1_create();
|
||||||
|
if (!config)
|
||||||
|
return;
|
||||||
|
if (!wlr_output_configuration_head_v1_create(config, server.output)) {
|
||||||
|
wlr_output_configuration_v1_destroy(config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wlr_output_manager_v1_set_configuration(server.output_mgr, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-publish after a commit changed the output size. Resizes land
|
||||||
|
lazily (host configures, client applies), so the commit -- not the
|
||||||
|
request -- is where the new size becomes observable. */
|
||||||
|
static void output_mgmt_sync(void) {
|
||||||
|
if (!server.output_mgr || !server.output)
|
||||||
|
return;
|
||||||
|
static int last_w = -1, last_h = -1;
|
||||||
|
if (server.output->width == last_w && server.output->height == last_h)
|
||||||
|
return;
|
||||||
|
last_w = server.output->width;
|
||||||
|
last_h = server.output->height;
|
||||||
|
output_mgmt_publish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The config head addressing our output, if the client included it. */
|
||||||
|
static struct wlr_output_configuration_head_v1 *mgmt_head_for_output(
|
||||||
|
struct wlr_output_configuration_v1 *config) {
|
||||||
|
if (!server.output)
|
||||||
|
return NULL;
|
||||||
|
struct wlr_output_configuration_head_v1 *h;
|
||||||
|
wl_list_for_each(h, &config->heads, link) {
|
||||||
|
if (h->state.output == server.output)
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Requested size, preferring an explicit mode over a custom one. */
|
||||||
|
static void mgmt_head_size(struct wlr_output_configuration_head_v1 *h,
|
||||||
|
int *w, int *hh) {
|
||||||
|
if (h->state.mode) {
|
||||||
|
*w = h->state.mode->width;
|
||||||
|
*hh = h->state.mode->height;
|
||||||
|
} else {
|
||||||
|
*w = h->state.custom_mode.width;
|
||||||
|
*hh = h->state.custom_mode.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whether a client config is one we can honor: our output, still
|
||||||
|
enabled, same scale/transform, sane size. Nested additionally
|
||||||
|
requires the live size (the host owns it). */
|
||||||
|
static bool mgmt_config_ok(struct wlr_output_configuration_v1 *config,
|
||||||
|
int *w, int *hh) {
|
||||||
|
struct wlr_output_configuration_head_v1 *h =
|
||||||
|
mgmt_head_for_output(config);
|
||||||
|
if (!h || !h->state.enabled || !server.output)
|
||||||
|
return false;
|
||||||
|
mgmt_head_size(h, w, hh);
|
||||||
|
if (*w < 50 || *hh < 50 || *w > 16384 || *hh > 16384)
|
||||||
|
return false;
|
||||||
|
if (h->state.scale != (float)server.output->scale ||
|
||||||
|
h->state.transform != server.output->transform)
|
||||||
|
return false;
|
||||||
|
if (!server.standalone &&
|
||||||
|
(*w != server.output->width || *hh != server.output->height))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_mgr_test(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_output_configuration_v1 *config = data;
|
||||||
|
int w = 0, hh = 0;
|
||||||
|
bool ok = mgmt_config_ok(config, &w, &hh);
|
||||||
|
if (ok && server.standalone) {
|
||||||
|
/* Honest modeset probe on top of the sanity check. */
|
||||||
|
struct wlr_output_state state;
|
||||||
|
wlr_output_state_init(&state);
|
||||||
|
wlr_output_state_set_custom_mode(&state, w, hh, 0);
|
||||||
|
ok = wlr_output_test_state(server.output, &state);
|
||||||
|
wlr_output_state_finish(&state);
|
||||||
|
}
|
||||||
|
kick_log(KICK_LOG_DEBUG, "[output] test %dx%d %s\n", w, hh,
|
||||||
|
ok ? "ok" : "failed");
|
||||||
|
if (ok)
|
||||||
|
wlr_output_configuration_v1_send_succeeded(config);
|
||||||
|
else
|
||||||
|
wlr_output_configuration_v1_send_failed(config);
|
||||||
|
wlr_output_configuration_v1_destroy(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_mgr_apply(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
(void)listener;
|
||||||
|
struct wlr_output_configuration_v1 *config = data;
|
||||||
|
int w = 0, hh = 0;
|
||||||
|
bool ok = mgmt_config_ok(config, &w, &hh);
|
||||||
|
if (ok && server.standalone) {
|
||||||
|
struct wlr_output_state state;
|
||||||
|
wlr_output_state_init(&state);
|
||||||
|
wlr_output_state_set_custom_mode(&state, w, hh, 0);
|
||||||
|
ok = wlr_output_test_state(server.output, &state);
|
||||||
|
wlr_output_state_finish(&state);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
if (server.standalone)
|
||||||
|
output_resize(w, hh);
|
||||||
|
output_mgmt_publish();
|
||||||
|
kick_log(KICK_LOG_INFO, "[output] apply %dx%d\n", w, hh);
|
||||||
|
wlr_output_configuration_v1_send_succeeded(config);
|
||||||
|
} else {
|
||||||
|
kick_log(KICK_LOG_INFO, "[output] apply %dx%d refused\n", w, hh);
|
||||||
|
wlr_output_configuration_v1_send_failed(config);
|
||||||
|
}
|
||||||
|
wlr_output_configuration_v1_destroy(config);
|
||||||
|
}
|
||||||
|
|
||||||
/* Gamma control: apply the client's ramp to the single output (or reset it
|
/* Gamma control: apply the client's ramp to the single output (or reset it
|
||||||
when the control went away: wlroots emits set_gamma with NULL then). A
|
when the control went away: wlroots emits set_gamma with NULL then). A
|
||||||
failed commit fails the control so the client (wlsunset) retries later
|
failed commit fails the control so the client (wlsunset) retries later
|
||||||
|
|
@ -10063,6 +10222,8 @@ static void render_standalone(void) {
|
||||||
apply_tearing_hint(&state);
|
apply_tearing_hint(&state);
|
||||||
if (!wlr_output_commit_state(server.output, &state))
|
if (!wlr_output_commit_state(server.output, &state))
|
||||||
kick_log(KICK_LOG_DEBUG, "[render] output commit failed\n");
|
kick_log(KICK_LOG_DEBUG, "[render] output commit failed\n");
|
||||||
|
else
|
||||||
|
output_mgmt_sync();
|
||||||
|
|
||||||
frame_done:
|
frame_done:
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
@ -10147,6 +10308,8 @@ static void render_and_present(void) {
|
||||||
apply_tearing_hint(&state);
|
apply_tearing_hint(&state);
|
||||||
if (!wlr_output_commit_state(server.output, &state))
|
if (!wlr_output_commit_state(server.output, &state))
|
||||||
kick_log(KICK_LOG_DEBUG, "[render] output commit failed\n");
|
kick_log(KICK_LOG_DEBUG, "[render] output commit failed\n");
|
||||||
|
else
|
||||||
|
output_mgmt_sync();
|
||||||
|
|
||||||
frame_done:
|
frame_done:
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
@ -11189,6 +11352,14 @@ int main(int argc, char *argv[]) {
|
||||||
wl_signal_add(&server.output_power_mgr->events.set_mode,
|
wl_signal_add(&server.output_power_mgr->events.set_mode,
|
||||||
&server.output_power_set_mode);
|
&server.output_power_set_mode);
|
||||||
|
|
||||||
|
/* Output management: publish the single head; client resizes apply
|
||||||
|
standalone and are refused nested (see the section). */
|
||||||
|
server.output_mgr = wlr_output_manager_v1_create(server.wl_display);
|
||||||
|
server.output_mgr_apply.notify = handle_output_mgr_apply;
|
||||||
|
wl_signal_add(&server.output_mgr->events.apply, &server.output_mgr_apply);
|
||||||
|
server.output_mgr_test.notify = handle_output_mgr_test;
|
||||||
|
wl_signal_add(&server.output_mgr->events.test, &server.output_mgr_test);
|
||||||
|
|
||||||
/* Gamma control: night-light clients set the output ramp (see
|
/* Gamma control: night-light clients set the output ramp (see
|
||||||
handle_gamma_set); wlroots itself fails controls for outputs with
|
handle_gamma_set); wlroots itself fails controls for outputs with
|
||||||
no LUT, so headless/nested clients learn it is unsupported. */
|
no LUT, so headless/nested clients learn it is unsupported. */
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,12 @@ protocols = {
|
||||||
wl_protocols_dir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml',
|
wl_protocols_dir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml',
|
||||||
'xdg-toplevel-icon-v1',
|
'xdg-toplevel-icon-v1',
|
||||||
],
|
],
|
||||||
|
# Output management (kanshi/wdisplays reconfigure the output):
|
||||||
|
# wlroots extension, vendored like the other wlr-protocols XMLs.
|
||||||
|
'output-management': [
|
||||||
|
'wlr-protocols/wlr-output-management-unstable-v1.xml',
|
||||||
|
'wlr-output-management-unstable-v1',
|
||||||
|
],
|
||||||
# Content hints (photo/video/game) + single-pixel buffers (1x1 solid
|
# Content hints (photo/video/game) + single-pixel buffers (1x1 solid
|
||||||
# color without a shm pool). Both are staging protocols from the
|
# color without a shm pool). Both are staging protocols from the
|
||||||
# system wayland-protocols, like wlroots itself uses.
|
# system wayland-protocols, like wlroots itself uses.
|
||||||
|
|
@ -396,6 +402,7 @@ executable('wltest',
|
||||||
code_by_name['xdg-dialog'],
|
code_by_name['xdg-dialog'],
|
||||||
code_by_name['pointer-gestures'],
|
code_by_name['pointer-gestures'],
|
||||||
code_by_name['toplevel-icon'],
|
code_by_name['toplevel-icon'],
|
||||||
|
code_by_name['output-management'],
|
||||||
client_headers['xdg-shell'],
|
client_headers['xdg-shell'],
|
||||||
client_headers['cursor-shape'],
|
client_headers['cursor-shape'],
|
||||||
client_headers['wlr-layer-shell-unstable-v1'],
|
client_headers['wlr-layer-shell-unstable-v1'],
|
||||||
|
|
@ -420,6 +427,7 @@ executable('wltest',
|
||||||
client_headers['tearing-control'],
|
client_headers['tearing-control'],
|
||||||
client_headers['fractional-scale'],
|
client_headers['fractional-scale'],
|
||||||
client_headers['toplevel-icon'],
|
client_headers['toplevel-icon'],
|
||||||
|
client_headers['output-management'],
|
||||||
dependencies: [dependency('wayland-client'),
|
dependencies: [dependency('wayland-client'),
|
||||||
dependency('xkbcommon')])
|
dependency('xkbcommon')])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1516,6 +1516,85 @@ def test_standalone_headless_toplevel_icon_preferred(tmp_path):
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_standalone_headless_output_mgmt_globals(tmp_path):
|
||||||
|
"""The standalone compositor advertises zwlr_output_manager_v1 so
|
||||||
|
display tools can list and reconfigure the output."""
|
||||||
|
out = tmp_path / "globals.txt"
|
||||||
|
s = _spawn_standalone({}, "%s --globals-out '%s' '#112233'" % (WL, out))
|
||||||
|
try:
|
||||||
|
deadline = time.monotonic() + 15.0
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
if out.exists():
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
assert out.exists(), "wltest --globals-out never wrote its file"
|
||||||
|
names = {line.split()[0] for line in out.read_text().splitlines()}
|
||||||
|
assert "zwlr_output_manager_v1" in names, \
|
||||||
|
f"missing output-mgmt global; advertised: {sorted(names)}"
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_standalone_headless_output_mgmt_list(tmp_path):
|
||||||
|
"""A management client learns the head (name + live size); the plain
|
||||||
|
color tab keeps the session up after the lister exits."""
|
||||||
|
out = tmp_path / "om.out"
|
||||||
|
s = _spawn_standalone(
|
||||||
|
{}, "%s --output-mgmt --output-mgmt-out '%s'" % (WL, out),
|
||||||
|
"%s '#ff0000'" % WL)
|
||||||
|
try:
|
||||||
|
s.wait_any_active()
|
||||||
|
deadline = time.monotonic() + 15.0
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
if out.exists():
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
assert out.exists(), "output-mgmt lister never wrote its file"
|
||||||
|
assert re.search(r"^head \S+ \d+x\d+$", out.read_text(),
|
||||||
|
re.MULTILINE), \
|
||||||
|
f"no head line in: {out.read_text()!r}"
|
||||||
|
assert s.proc.poll() is None, f"log tail:\n{s.read_log()[-400:]}"
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_standalone_headless_output_mgmt_apply(tmp_path):
|
||||||
|
"""Applying 800x600 through output-management resizes the session:
|
||||||
|
the client sees before/applied/after and a tab commits at 800x600."""
|
||||||
|
out = tmp_path / "om.out"
|
||||||
|
s = _spawn_standalone(
|
||||||
|
{},
|
||||||
|
"%s --output-mgmt --output-mgmt-out '%s' --output-mgmt-size 800x600"
|
||||||
|
% (WL, out),
|
||||||
|
"%s '#ff0000'" % WL)
|
||||||
|
try:
|
||||||
|
s.wait_any_active()
|
||||||
|
deadline = time.monotonic() + 20.0
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
if out.exists() and "after " in out.read_text():
|
||||||
|
break
|
||||||
|
time.sleep(0.2)
|
||||||
|
text = out.read_text() if out.exists() else ""
|
||||||
|
assert "before " in text, f"no before line in: {text!r}"
|
||||||
|
assert "applied" in text, f"apply not acked in: {text!r}"
|
||||||
|
m = re.search(r"^after \S+ (\d+)x(\d+)$", text, re.MULTILINE)
|
||||||
|
assert m and (m.group(1), m.group(2)) == ("800", "600"), \
|
||||||
|
f"no 800x600 after line in: {text!r}"
|
||||||
|
# A live tab reflows into the new output size.
|
||||||
|
deadline = time.monotonic() + 15.0
|
||||||
|
geom = None
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
if re.search(r"\[diag\] commit app=\d+ geom=800x600",
|
||||||
|
s.read_log()):
|
||||||
|
geom = True
|
||||||
|
break
|
||||||
|
time.sleep(0.2)
|
||||||
|
assert geom, "no tab committed at 800x600"
|
||||||
|
assert s.proc.poll() is None, f"log tail:\n{s.read_log()[-400:]}"
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
def test_standalone_headless_gestures_globals(tmp_path):
|
def test_standalone_headless_gestures_globals(tmp_path):
|
||||||
"""The standalone compositor advertises zwp_pointer_gestures_v1 so
|
"""The standalone compositor advertises zwp_pointer_gestures_v1 so
|
||||||
touchpad clients can bind swipe/pinch/hold."""
|
touchpad clients can bind swipe/pinch/hold."""
|
||||||
|
|
|
||||||
293
tests/wltest.c
293
tests/wltest.c
|
|
@ -43,6 +43,7 @@
|
||||||
#include "tearing-control-v1-client.h"
|
#include "tearing-control-v1-client.h"
|
||||||
#include "fractional-scale-v1-client.h"
|
#include "fractional-scale-v1-client.h"
|
||||||
#include "xdg-toplevel-icon-v1-client.h"
|
#include "xdg-toplevel-icon-v1-client.h"
|
||||||
|
#include "wlr-output-management-unstable-v1-client.h"
|
||||||
|
|
||||||
/* Minimal deterministic xdg toplevel test client: shows a solid-color shm
|
/* Minimal deterministic xdg toplevel test client: shows a solid-color shm
|
||||||
buffer and runs until killed. Used by test.sh to give the smoke test two
|
buffer and runs until killed. Used by test.sh to give the smoke test two
|
||||||
|
|
@ -152,6 +153,7 @@ static struct xdg_activation_v1 *activation_mgr;
|
||||||
static struct xdg_wm_dialog_v1 *dialog_mgr;
|
static struct xdg_wm_dialog_v1 *dialog_mgr;
|
||||||
static struct zwp_pointer_gestures_v1 *gestures_mgr;
|
static struct zwp_pointer_gestures_v1 *gestures_mgr;
|
||||||
static struct xdg_toplevel_icon_manager_v1 *toplevel_icon_mgr;
|
static struct xdg_toplevel_icon_manager_v1 *toplevel_icon_mgr;
|
||||||
|
static struct zwlr_output_manager_v1 *output_mgr;
|
||||||
static struct wp_tearing_control_manager_v1 *tearing_mgr;
|
static struct wp_tearing_control_manager_v1 *tearing_mgr;
|
||||||
static struct wp_fractional_scale_manager_v1 *fractional_mgr;
|
static struct wp_fractional_scale_manager_v1 *fractional_mgr;
|
||||||
static struct zwp_text_input_manager_v3 *text_input_mgr;
|
static struct zwp_text_input_manager_v3 *text_input_mgr;
|
||||||
|
|
@ -839,6 +841,11 @@ static void registry_global(void *data, struct wl_registry *reg, uint32_t name,
|
||||||
toplevel_icon_mgr = wl_registry_bind(reg, name,
|
toplevel_icon_mgr = wl_registry_bind(reg, name,
|
||||||
&xdg_toplevel_icon_manager_v1_interface,
|
&xdg_toplevel_icon_manager_v1_interface,
|
||||||
version < 1 ? version : 1);
|
version < 1 ? version : 1);
|
||||||
|
} else if (strcmp(interface,
|
||||||
|
zwlr_output_manager_v1_interface.name) == 0) {
|
||||||
|
output_mgr = wl_registry_bind(reg, name,
|
||||||
|
&zwlr_output_manager_v1_interface,
|
||||||
|
version < 4 ? version : 4);
|
||||||
} else if (strcmp(interface,
|
} else if (strcmp(interface,
|
||||||
wp_tearing_control_manager_v1_interface.name) == 0) {
|
wp_tearing_control_manager_v1_interface.name) == 0) {
|
||||||
tearing_mgr = wl_registry_bind(reg, name,
|
tearing_mgr = wl_registry_bind(reg, name,
|
||||||
|
|
@ -1701,10 +1708,255 @@ static void gesture_bind_all(void) {
|
||||||
zwp_pointer_gesture_hold_v1_add_listener(ho, &hold_listener, NULL);
|
zwp_pointer_gesture_hold_v1_add_listener(ho, &hold_listener, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Output management (wlr-output-management) ---
|
||||||
|
--output-mgmt --output-mgmt-out <file> [--output-mgmt-size WxH]:
|
||||||
|
list the head (name + current size) into <file>; with a size, apply
|
||||||
|
it as a custom mode first and record before/after/applied. No window
|
||||||
|
is opened. */
|
||||||
|
static bool output_mgmt_mode;
|
||||||
|
static const char *output_mgmt_out;static int output_mgmt_w, output_mgmt_h;
|
||||||
|
static bool output_mgmt_want_size;
|
||||||
|
static struct zwlr_output_head_v1 *om_head;
|
||||||
|
static char om_name[64];
|
||||||
|
static bool om_applied;
|
||||||
|
static struct {
|
||||||
|
struct zwlr_output_mode_v1 *res;
|
||||||
|
int w, h;
|
||||||
|
} om_modes[32];
|
||||||
|
static int om_nmodes;
|
||||||
|
static struct zwlr_output_mode_v1 *om_current;
|
||||||
|
static const struct zwlr_output_head_v1_listener om_head_listener;
|
||||||
|
static const struct zwlr_output_mode_v1_listener om_mode_listener;
|
||||||
|
|
||||||
|
static void om_note(const char *fmt, ...) {
|
||||||
|
if (!output_mgmt_out)
|
||||||
|
return;
|
||||||
|
FILE *f = fopen(output_mgmt_out, "a");
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(f, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fputc('\n', f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int om_mode_size(struct zwlr_output_mode_v1 *res, int *w, int *h) {
|
||||||
|
for (int i = 0; i < om_nmodes; i++)
|
||||||
|
if (om_modes[i].res == res) {
|
||||||
|
*w = om_modes[i].w;
|
||||||
|
*h = om_modes[i].h;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_report_head(const char *tag) {
|
||||||
|
int w = 0, h = 0;
|
||||||
|
if (om_mode_size(om_current, &w, &h) == 0)
|
||||||
|
om_note("%s %s %dx%d", tag, om_name[0] ? om_name : "?", w, h);
|
||||||
|
else
|
||||||
|
om_note("%s %s ?", tag, om_name[0] ? om_name : "?");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_config_succeeded(void *data,
|
||||||
|
struct zwlr_output_configuration_v1 *cfg) {
|
||||||
|
(void)data; (void)cfg;
|
||||||
|
om_note("applied");
|
||||||
|
om_applied = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_config_failed(void *data,
|
||||||
|
struct zwlr_output_configuration_v1 *cfg) {
|
||||||
|
(void)data; (void)cfg;
|
||||||
|
om_note("failed");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_config_cancelled(void *data,
|
||||||
|
struct zwlr_output_configuration_v1 *cfg) {
|
||||||
|
(void)data; (void)cfg;
|
||||||
|
/* Superseded by a newer configuration (e.g. a concurrent modeset):
|
||||||
|
wait for the fresh done and retry with its serial, bounded. */
|
||||||
|
static int retries;
|
||||||
|
if (++retries > 3) {
|
||||||
|
om_note("cancelled");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
om_applied = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_configuration_v1_listener om_config_listener = {
|
||||||
|
.succeeded = om_config_succeeded,
|
||||||
|
.failed = om_config_failed,
|
||||||
|
.cancelled = om_config_cancelled,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void om_mgr_head(void *data, struct zwlr_output_manager_v1 *mgr,
|
||||||
|
struct zwlr_output_head_v1 *head) {
|
||||||
|
(void)data; (void)mgr;
|
||||||
|
if (!om_head) {
|
||||||
|
om_head = head;
|
||||||
|
zwlr_output_head_v1_add_listener(head, &om_head_listener, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_head_name(void *data, struct zwlr_output_head_v1 *head,
|
||||||
|
const char *name) {
|
||||||
|
(void)data; (void)head;
|
||||||
|
snprintf(om_name, sizeof(om_name), "%s", name ? name : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_noop_head_str(void *data, struct zwlr_output_head_v1 *head,
|
||||||
|
const char *s) {
|
||||||
|
(void)data; (void)head; (void)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_noop_head_u32(void *data, struct zwlr_output_head_v1 *head,
|
||||||
|
uint32_t v) {
|
||||||
|
(void)data; (void)head; (void)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_noop_head_i32x2(void *data, struct zwlr_output_head_v1 *head,
|
||||||
|
int32_t a, int32_t b) {
|
||||||
|
(void)data; (void)head; (void)a; (void)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_noop_head_i32(void *data, struct zwlr_output_head_v1 *head,
|
||||||
|
int32_t v) {
|
||||||
|
(void)data; (void)head; (void)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_head_mode(void *data, struct zwlr_output_head_v1 *head,
|
||||||
|
struct zwlr_output_mode_v1 *mode) {
|
||||||
|
(void)data; (void)head;
|
||||||
|
if (om_nmodes < 32) {
|
||||||
|
om_modes[om_nmodes].res = mode;
|
||||||
|
om_modes[om_nmodes].w = 0;
|
||||||
|
om_modes[om_nmodes].h = 0;
|
||||||
|
om_nmodes++;
|
||||||
|
zwlr_output_mode_v1_add_listener(mode, &om_mode_listener, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_head_current_mode(void *data,
|
||||||
|
struct zwlr_output_head_v1 *head,
|
||||||
|
struct zwlr_output_mode_v1 *mode) {
|
||||||
|
(void)data; (void)head;
|
||||||
|
om_current = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_head_finished(void *data, struct zwlr_output_head_v1 *head) {
|
||||||
|
(void)data; (void)head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_head_v1_listener om_head_listener = {
|
||||||
|
.name = om_head_name,
|
||||||
|
.description = om_noop_head_str,
|
||||||
|
.physical_size = om_noop_head_i32x2,
|
||||||
|
.mode = om_head_mode,
|
||||||
|
.enabled = om_noop_head_i32,
|
||||||
|
.current_mode = om_head_current_mode,
|
||||||
|
.position = om_noop_head_i32x2,
|
||||||
|
.transform = om_noop_head_i32,
|
||||||
|
.scale = om_noop_head_i32,
|
||||||
|
.finished = om_head_finished,
|
||||||
|
.make = om_noop_head_str,
|
||||||
|
.model = om_noop_head_str,
|
||||||
|
.serial_number = om_noop_head_str,
|
||||||
|
.adaptive_sync = om_noop_head_u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void om_mode_size_ev(void *data, struct zwlr_output_mode_v1 *mode,
|
||||||
|
int32_t w, int32_t h) {
|
||||||
|
(void)data;
|
||||||
|
for (int i = 0; i < om_nmodes; i++)
|
||||||
|
if (om_modes[i].res == mode) {
|
||||||
|
om_modes[i].w = w;
|
||||||
|
om_modes[i].h = h;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_noop_mode_i32(void *data, struct zwlr_output_mode_v1 *mode,
|
||||||
|
int32_t v) {
|
||||||
|
(void)data; (void)mode; (void)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_noop_mode_void(void *data, struct zwlr_output_mode_v1 *mode) {
|
||||||
|
(void)data; (void)mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_mode_v1_listener om_mode_listener = {
|
||||||
|
.size = om_mode_size_ev,
|
||||||
|
.refresh = om_noop_mode_i32,
|
||||||
|
.preferred = om_noop_mode_void,
|
||||||
|
.finished = om_noop_mode_void,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void om_mgr_done(void *data, struct zwlr_output_manager_v1 *mgr,
|
||||||
|
uint32_t serial) {
|
||||||
|
(void)data; (void)mgr;
|
||||||
|
if (output_mgmt_want_size && !om_applied && om_head) {
|
||||||
|
int w = 0, h = 0;
|
||||||
|
if (om_mode_size(om_current, &w, &h) == 0 &&
|
||||||
|
(w != output_mgmt_w || h != output_mgmt_h)) {
|
||||||
|
om_report_head("before");
|
||||||
|
struct zwlr_output_configuration_v1 *cfg =
|
||||||
|
zwlr_output_manager_v1_create_configuration(output_mgr,
|
||||||
|
serial);
|
||||||
|
zwlr_output_configuration_v1_add_listener(cfg,
|
||||||
|
&om_config_listener, NULL);
|
||||||
|
struct zwlr_output_configuration_head_v1 *chead =
|
||||||
|
zwlr_output_configuration_v1_enable_head(cfg, om_head);
|
||||||
|
zwlr_output_configuration_head_v1_set_custom_mode(
|
||||||
|
chead, output_mgmt_w, output_mgmt_h, 0);
|
||||||
|
zwlr_output_configuration_v1_apply(cfg);
|
||||||
|
wl_display_flush(display);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
om_report_head(om_applied ? "after" : "head");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void om_mgr_finished(void *data,
|
||||||
|
struct zwlr_output_manager_v1 *mgr) {
|
||||||
|
(void)data; (void)mgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_manager_v1_listener om_mgr_listener = {
|
||||||
|
.head = om_mgr_head,
|
||||||
|
.done = om_mgr_done,
|
||||||
|
.finished = om_mgr_finished,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void output_mgmt_run(void) {
|
||||||
|
display = wl_display_connect(NULL);
|
||||||
|
if (!display) {
|
||||||
|
fprintf(stderr, "wltest: output-mgmt: cannot connect\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
struct wl_registry *reg = wl_display_get_registry(display);
|
||||||
|
wl_registry_add_listener(reg, ®istry_listener, NULL);
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
if (!output_mgr) {
|
||||||
|
fprintf(stderr, "wltest: output-mgmt: manager missing\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
zwlr_output_manager_v1_add_listener(output_mgr, &om_mgr_listener, NULL);
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
for (;;) {
|
||||||
|
if (wl_display_dispatch(display) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* --- Toplevel icon ---
|
/* --- Toplevel icon ---
|
||||||
--icon <#RRGGBB> [SIZE]: upload a SIZE×SIZE (default 8) solid-color
|
--icon <#RRGGBB> [SIZE]: upload a SIZE×SIZE (default 8) solid-color
|
||||||
icon buffer and set it on the toplevel via xdg-toplevel-icon-v1. */
|
icon buffer and set it on the toplevel via xdg-toplevel-icon-v1. */static uint8_t ICON_PIXEL[4] = { 0x00, 0xff, 0x00, 0xff }; /* RGBA */
|
||||||
static uint8_t ICON_PIXEL[4] = { 0x00, 0xff, 0x00, 0xff }; /* RGBA */
|
|
||||||
static int icon_size;
|
static int icon_size;
|
||||||
static bool want_icon;
|
static bool want_icon;
|
||||||
|
|
||||||
|
|
@ -2464,6 +2716,8 @@ static void print_usage(const char *argv0) {
|
||||||
"[--dialog-modal] [--extra-modal] [--extra-delay <ms>] "
|
"[--dialog-modal] [--extra-modal] [--extra-delay <ms>] "
|
||||||
"[--tearing <vsync|async>] [--fractional-out <file>] "
|
"[--tearing <vsync|async>] [--fractional-out <file>] "
|
||||||
"[--icon <#RRGGBB> [SIZE]] "
|
"[--icon <#RRGGBB> [SIZE]] "
|
||||||
|
"[--output-mgmt [--output-mgmt-out <file>] "
|
||||||
|
"[--output-mgmt-size <W>x<H>]] "
|
||||||
"#RRGGBB [WIDTHxHEIGHT]\n"
|
"#RRGGBB [WIDTHxHEIGHT]\n"
|
||||||
" %s shows a solid-color xdg_toplevel, e.g. #ff0000\n"
|
" %s shows a solid-color xdg_toplevel, e.g. #ff0000\n"
|
||||||
" --extra also opens a second toplevel from the same client\n"
|
" --extra also opens a second toplevel from the same client\n"
|
||||||
|
|
@ -2505,7 +2759,10 @@ static void print_usage(const char *argv0) {
|
||||||
" on the toplevel; --fractional-out writes the\n"
|
" on the toplevel; --fractional-out writes the\n"
|
||||||
" compositor's preferred_scale and exits\n"
|
" compositor's preferred_scale and exits\n"
|
||||||
" --icon uploads a SIZE×SIZE (default 8) solid-color\n"
|
" --icon uploads a SIZE×SIZE (default 8) solid-color\n"
|
||||||
" icon and sets it via xdg-toplevel-icon-v1",
|
" icon and sets it via xdg-toplevel-icon-v1\n"
|
||||||
|
" --output-mgmt lists the output head (name + size)\n"
|
||||||
|
" to --output-mgmt-out, applying --output-mgmt-size\n"
|
||||||
|
" first when given",
|
||||||
argv0, argv0);
|
argv0, argv0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2576,6 +2833,30 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
fractional_out = argv[i + 1];
|
fractional_out = argv[i + 1];
|
||||||
i += 2;
|
i += 2;
|
||||||
|
} else if (strcmp(argv[i], "--output-mgmt") == 0) {
|
||||||
|
output_mgmt_mode = true;
|
||||||
|
i += 1;
|
||||||
|
} else if (strcmp(argv[i], "--output-mgmt-out") == 0) {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
fprintf(stderr, "wltest: --output-mgmt-out needs a path\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
output_mgmt_out = argv[i + 1];
|
||||||
|
i += 2;
|
||||||
|
} else if (strcmp(argv[i], "--output-mgmt-size") == 0) {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
fprintf(stderr, "wltest: --output-mgmt-size needs WxH\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (sscanf(argv[i + 1], "%dx%d", &output_mgmt_w,
|
||||||
|
&output_mgmt_h) != 2 ||
|
||||||
|
output_mgmt_w <= 0 || output_mgmt_h <= 0) {
|
||||||
|
fprintf(stderr, "wltest: bad --output-mgmt-size '%s'\n",
|
||||||
|
argv[i + 1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
output_mgmt_want_size = true;
|
||||||
|
i += 2;
|
||||||
} else if (strcmp(argv[i], "--icon") == 0) {
|
} else if (strcmp(argv[i], "--icon") == 0) {
|
||||||
if (i + 1 >= argc) {
|
if (i + 1 >= argc) {
|
||||||
fprintf(stderr, "wltest: --icon needs a color\n");
|
fprintf(stderr, "wltest: --icon needs a color\n");
|
||||||
|
|
@ -2981,6 +3262,12 @@ int main(int argc, char **argv) {
|
||||||
gamma_run();
|
gamma_run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Output-management mode: no color/size argument. List the head
|
||||||
|
and optionally apply a custom size, then exit. */
|
||||||
|
if (output_mgmt_mode) {
|
||||||
|
output_mgmt_run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/* Shortcuts-inhibit mode: act as a game window that grabs the
|
/* Shortcuts-inhibit mode: act as a game window that grabs the
|
||||||
compositor's shortcuts. Creates its own focused window. */
|
compositor's shortcuts. Creates its own focused window. */
|
||||||
if (inhibit_mode) {
|
if (inhibit_mode) {
|
||||||
|
|
|
||||||
601
wlr-protocols/wlr-output-management-unstable-v1.xml
Normal file
601
wlr-protocols/wlr-output-management-unstable-v1.xml
Normal file
|
|
@ -0,0 +1,601 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_output_management_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2019 Purism SPC
|
||||||
|
|
||||||
|
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="protocol to configure output devices">
|
||||||
|
This protocol exposes interfaces to obtain and modify output device
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
|
may be added together with the corresponding interface version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version number in
|
||||||
|
the protocol and interface names and resetting the interface version.
|
||||||
|
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
|
||||||
|
interface version number is reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_manager_v1" version="4">
|
||||||
|
<description summary="output device configuration manager">
|
||||||
|
This interface is a manager that allows reading and writing the current
|
||||||
|
output device configuration.
|
||||||
|
|
||||||
|
Output devices that display pixels (e.g. a physical monitor or a virtual
|
||||||
|
output in a window) are represented as heads. Heads cannot be created nor
|
||||||
|
destroyed by the client, but they can be enabled or disabled and their
|
||||||
|
properties can be changed. Each head may have one or more available modes.
|
||||||
|
|
||||||
|
Whenever a head appears (e.g. a monitor is plugged in), it will be
|
||||||
|
advertised via the head event. Immediately after the output manager is
|
||||||
|
bound, all current heads are advertised.
|
||||||
|
|
||||||
|
Whenever a head's properties change, the relevant wlr_output_head events
|
||||||
|
will be sent. Not all head properties will be sent: only properties that
|
||||||
|
have changed need to.
|
||||||
|
|
||||||
|
Whenever a head disappears (e.g. a monitor is unplugged), a
|
||||||
|
wlr_output_head.finished event will be sent.
|
||||||
|
|
||||||
|
After one or more heads appear, change or disappear, the done event will
|
||||||
|
be sent. It carries a serial which can be used in a create_configuration
|
||||||
|
request to update heads properties.
|
||||||
|
|
||||||
|
The information obtained from this protocol should only be used for output
|
||||||
|
configuration purposes. This protocol is not designed to be a generic
|
||||||
|
output property advertisement protocol for regular clients. Instead,
|
||||||
|
protocols such as xdg-output should be used.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="head">
|
||||||
|
<description summary="introduce a new head">
|
||||||
|
This event introduces a new head. This happens whenever a new head
|
||||||
|
appears (e.g. a monitor is plugged in) or after the output manager is
|
||||||
|
bound.
|
||||||
|
</description>
|
||||||
|
<arg name="head" type="new_id" interface="zwlr_output_head_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="done">
|
||||||
|
<description summary="sent all information about current configuration">
|
||||||
|
This event is sent after all information has been sent after binding to
|
||||||
|
the output manager object and after any subsequent changes. This applies
|
||||||
|
to child head and mode objects as well. In other words, this event is
|
||||||
|
sent whenever a head or mode is created or destroyed and whenever one of
|
||||||
|
their properties has been changed. Not all state is re-sent each time
|
||||||
|
the current configuration changes: only the actual changes are sent.
|
||||||
|
|
||||||
|
This allows changes to the output configuration to be seen as atomic,
|
||||||
|
even if they happen via multiple events.
|
||||||
|
|
||||||
|
A serial is sent to be used in a future create_configuration request.
|
||||||
|
</description>
|
||||||
|
<arg name="serial" type="uint" summary="current configuration serial"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="create_configuration">
|
||||||
|
<description summary="create a new output configuration object">
|
||||||
|
Create a new output configuration object. This allows to update head
|
||||||
|
properties.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_output_configuration_v1"/>
|
||||||
|
<arg name="serial" type="uint"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="stop">
|
||||||
|
<description summary="stop sending events">
|
||||||
|
Indicates the client no longer wishes to receive events for output
|
||||||
|
configuration changes. However the compositor may emit further events,
|
||||||
|
until the finished event is emitted.
|
||||||
|
|
||||||
|
The client must not send any more requests after this one.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="finished" type="destructor">
|
||||||
|
<description summary="the compositor has finished with the manager">
|
||||||
|
This event indicates that the compositor is done sending manager events.
|
||||||
|
The compositor will destroy the object immediately after sending this
|
||||||
|
event, so it will become invalid and the client should release any
|
||||||
|
resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_head_v1" version="4">
|
||||||
|
<description summary="output device">
|
||||||
|
A head is an output device. The difference between a wl_output object and
|
||||||
|
a head is that heads are advertised even if they are turned off. A head
|
||||||
|
object only advertises properties and cannot be used directly to change
|
||||||
|
them.
|
||||||
|
|
||||||
|
A head has some read-only properties: modes, name, description and
|
||||||
|
physical_size. These cannot be changed by clients.
|
||||||
|
|
||||||
|
Other properties can be updated via a wlr_output_configuration object.
|
||||||
|
|
||||||
|
Properties sent via this interface are applied atomically via the
|
||||||
|
wlr_output_manager.done event. No guarantees are made regarding the order
|
||||||
|
in which properties are sent.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="name">
|
||||||
|
<description summary="head name">
|
||||||
|
This event describes the head name.
|
||||||
|
|
||||||
|
The naming convention is compositor defined, but limited to alphanumeric
|
||||||
|
characters and dashes (-). Each name is unique among all wlr_output_head
|
||||||
|
objects, but if a wlr_output_head object is destroyed the same name may
|
||||||
|
be reused later. The names will also remain consistent across sessions
|
||||||
|
with the same hardware and software configuration.
|
||||||
|
|
||||||
|
Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
|
||||||
|
not assume that the name is a reflection of an underlying DRM
|
||||||
|
connector, X11 connection, etc.
|
||||||
|
|
||||||
|
If the compositor implements the xdg-output protocol and this head is
|
||||||
|
enabled, the xdg_output.name event must report the same name.
|
||||||
|
|
||||||
|
The name event is sent after a wlr_output_head object is created. This
|
||||||
|
event is only sent once per object, and the name does not change over
|
||||||
|
the lifetime of the wlr_output_head object.
|
||||||
|
</description>
|
||||||
|
<arg name="name" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="description">
|
||||||
|
<description summary="head description">
|
||||||
|
This event describes a human-readable description of the head.
|
||||||
|
|
||||||
|
The description is a UTF-8 string with no convention defined for its
|
||||||
|
contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11
|
||||||
|
output via :1'. However, do not assume that the name is a reflection of
|
||||||
|
the make, model, serial of the underlying DRM connector or the display
|
||||||
|
name of the underlying X11 connection, etc.
|
||||||
|
|
||||||
|
If the compositor implements xdg-output and this head is enabled,
|
||||||
|
the xdg_output.description must report the same description.
|
||||||
|
|
||||||
|
The description event is sent after a wlr_output_head object is created.
|
||||||
|
This event is only sent once per object, and the description does not
|
||||||
|
change over the lifetime of the wlr_output_head object.
|
||||||
|
</description>
|
||||||
|
<arg name="description" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="physical_size">
|
||||||
|
<description summary="head physical size">
|
||||||
|
This event describes the physical size of the head. This event is only
|
||||||
|
sent if the head has a physical size (e.g. is not a projector or a
|
||||||
|
virtual device).
|
||||||
|
</description>
|
||||||
|
<arg name="width" type="int" summary="width in millimeters of the output"/>
|
||||||
|
<arg name="height" type="int" summary="height in millimeters of the output"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="mode">
|
||||||
|
<description summary="introduce a mode">
|
||||||
|
This event introduces a mode for this head. It is sent once per
|
||||||
|
supported mode.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="new_id" interface="zwlr_output_mode_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="enabled">
|
||||||
|
<description summary="head is enabled or disabled">
|
||||||
|
This event describes whether the head is enabled. A disabled head is not
|
||||||
|
mapped to a region of the global compositor space.
|
||||||
|
|
||||||
|
When a head is disabled, some properties (current_mode, position,
|
||||||
|
transform and scale) are irrelevant.
|
||||||
|
</description>
|
||||||
|
<arg name="enabled" type="int" summary="zero if disabled, non-zero if enabled"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="current_mode">
|
||||||
|
<description summary="current mode">
|
||||||
|
This event describes the mode currently in use for this head. It is only
|
||||||
|
sent if the output is enabled.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="object" interface="zwlr_output_mode_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="position">
|
||||||
|
<description summary="current position">
|
||||||
|
This events describes the position of the head in the global compositor
|
||||||
|
space. It is only sent if the output is enabled.
|
||||||
|
</description>
|
||||||
|
<arg name="x" type="int"
|
||||||
|
summary="x position within the global compositor space"/>
|
||||||
|
<arg name="y" type="int"
|
||||||
|
summary="y position within the global compositor space"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="transform">
|
||||||
|
<description summary="current transformation">
|
||||||
|
This event describes the transformation currently applied to the head.
|
||||||
|
It is only sent if the output is enabled.
|
||||||
|
</description>
|
||||||
|
<arg name="transform" type="int" enum="wl_output.transform"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="scale">
|
||||||
|
<description summary="current scale">
|
||||||
|
This events describes the scale of the head in the global compositor
|
||||||
|
space. It is only sent if the output is enabled.
|
||||||
|
</description>
|
||||||
|
<arg name="scale" type="fixed"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<description summary="the head has disappeared">
|
||||||
|
This event indicates that the head is no longer available. The head
|
||||||
|
object becomes inert. Clients should send a destroy request and release
|
||||||
|
any resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<!-- Version 2 additions -->
|
||||||
|
|
||||||
|
<event name="make" since="2">
|
||||||
|
<description summary="head manufacturer">
|
||||||
|
This event describes the manufacturer of the head.
|
||||||
|
|
||||||
|
This must report the same make as the wl_output interface does in its
|
||||||
|
geometry event.
|
||||||
|
|
||||||
|
Together with the model and serial_number events the purpose is to
|
||||||
|
allow clients to recognize heads from previous sessions and for example
|
||||||
|
load head-specific configurations back.
|
||||||
|
|
||||||
|
It is not guaranteed this event will be ever sent. A reason for that
|
||||||
|
can be that the compositor does not have information about the make of
|
||||||
|
the head or the definition of a make is not sensible in the current
|
||||||
|
setup, for example in a virtual session. Clients can still try to
|
||||||
|
identify the head by available information from other events but should
|
||||||
|
be aware that there is an increased risk of false positives.
|
||||||
|
|
||||||
|
It is not recommended to display the make string in UI to users. For
|
||||||
|
that the string provided by the description event should be preferred.
|
||||||
|
</description>
|
||||||
|
<arg name="make" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="model" since="2">
|
||||||
|
<description summary="head model">
|
||||||
|
This event describes the model of the head.
|
||||||
|
|
||||||
|
This must report the same model as the wl_output interface does in its
|
||||||
|
geometry event.
|
||||||
|
|
||||||
|
Together with the make and serial_number events the purpose is to
|
||||||
|
allow clients to recognize heads from previous sessions and for example
|
||||||
|
load head-specific configurations back.
|
||||||
|
|
||||||
|
It is not guaranteed this event will be ever sent. A reason for that
|
||||||
|
can be that the compositor does not have information about the model of
|
||||||
|
the head or the definition of a model is not sensible in the current
|
||||||
|
setup, for example in a virtual session. Clients can still try to
|
||||||
|
identify the head by available information from other events but should
|
||||||
|
be aware that there is an increased risk of false positives.
|
||||||
|
|
||||||
|
It is not recommended to display the model string in UI to users. For
|
||||||
|
that the string provided by the description event should be preferred.
|
||||||
|
</description>
|
||||||
|
<arg name="model" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="serial_number" since="2">
|
||||||
|
<description summary="head serial number">
|
||||||
|
This event describes the serial number of the head.
|
||||||
|
|
||||||
|
Together with the make and model events the purpose is to allow clients
|
||||||
|
to recognize heads from previous sessions and for example load head-
|
||||||
|
specific configurations back.
|
||||||
|
|
||||||
|
It is not guaranteed this event will be ever sent. A reason for that
|
||||||
|
can be that the compositor does not have information about the serial
|
||||||
|
number of the head or the definition of a serial number is not sensible
|
||||||
|
in the current setup. Clients can still try to identify the head by
|
||||||
|
available information from other events but should be aware that there
|
||||||
|
is an increased risk of false positives.
|
||||||
|
|
||||||
|
It is not recommended to display the serial_number string in UI to
|
||||||
|
users. For that the string provided by the description event should be
|
||||||
|
preferred.
|
||||||
|
</description>
|
||||||
|
<arg name="serial_number" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<!-- Version 3 additions -->
|
||||||
|
|
||||||
|
<request name="release" type="destructor" since="3">
|
||||||
|
<description summary="destroy the head object">
|
||||||
|
This request indicates that the client will no longer use this head
|
||||||
|
object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Version 4 additions -->
|
||||||
|
|
||||||
|
<enum name="adaptive_sync_state" since="4">
|
||||||
|
<entry name="disabled" value="0" summary="adaptive sync is disabled"/>
|
||||||
|
<entry name="enabled" value="1" summary="adaptive sync is enabled"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<event name="adaptive_sync" since="4">
|
||||||
|
<description summary="current adaptive sync state">
|
||||||
|
This event describes whether adaptive sync is currently enabled for
|
||||||
|
the head or not. Adaptive sync is also known as Variable Refresh
|
||||||
|
Rate or VRR.
|
||||||
|
</description>
|
||||||
|
<arg name="state" type="uint" enum="adaptive_sync_state"/>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_mode_v1" version="3">
|
||||||
|
<description summary="output mode">
|
||||||
|
This object describes an output mode.
|
||||||
|
|
||||||
|
Some heads don't support output modes, in which case modes won't be
|
||||||
|
advertised.
|
||||||
|
|
||||||
|
Properties sent via this interface are applied atomically via the
|
||||||
|
wlr_output_manager.done event. No guarantees are made regarding the order
|
||||||
|
in which properties are sent.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="size">
|
||||||
|
<description summary="mode size">
|
||||||
|
This event describes the mode size. The size is given in physical
|
||||||
|
hardware units of the output device. This is not necessarily the same as
|
||||||
|
the output size in the global compositor space. For instance, the output
|
||||||
|
may be scaled or transformed.
|
||||||
|
</description>
|
||||||
|
<arg name="width" type="int" summary="width of the mode in hardware units"/>
|
||||||
|
<arg name="height" type="int" summary="height of the mode in hardware units"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="refresh">
|
||||||
|
<description summary="mode refresh rate">
|
||||||
|
This event describes the mode's fixed vertical refresh rate. It is only
|
||||||
|
sent if the mode has a fixed refresh rate.
|
||||||
|
</description>
|
||||||
|
<arg name="refresh" type="int" summary="vertical refresh rate in mHz"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="preferred">
|
||||||
|
<description summary="mode is preferred">
|
||||||
|
This event advertises this mode as preferred.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<description summary="the mode has disappeared">
|
||||||
|
This event indicates that the mode is no longer available. The mode
|
||||||
|
object becomes inert. Clients should send a destroy request and release
|
||||||
|
any resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<!-- Version 3 additions -->
|
||||||
|
|
||||||
|
<request name="release" type="destructor" since="3">
|
||||||
|
<description summary="destroy the mode object">
|
||||||
|
This request indicates that the client will no longer use this mode
|
||||||
|
object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_configuration_v1" version="4">
|
||||||
|
<description summary="output configuration">
|
||||||
|
This object is used by the client to describe a full output configuration.
|
||||||
|
|
||||||
|
First, the client needs to setup the output configuration. Each head can
|
||||||
|
be either enabled (and configured) or disabled. It is a protocol error to
|
||||||
|
send two enable_head or disable_head requests with the same head. It is a
|
||||||
|
protocol error to omit a head in a configuration.
|
||||||
|
|
||||||
|
Then, the client can apply or test the configuration. The compositor will
|
||||||
|
then reply with a succeeded, failed or cancelled event. Finally the client
|
||||||
|
should destroy the configuration object.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_configured_head" value="1"
|
||||||
|
summary="head has been configured twice"/>
|
||||||
|
<entry name="unconfigured_head" value="2"
|
||||||
|
summary="head has not been configured"/>
|
||||||
|
<entry name="already_used" value="3"
|
||||||
|
summary="request sent after configuration has been applied or tested"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="enable_head">
|
||||||
|
<description summary="enable and configure a head">
|
||||||
|
Enable a head. This request creates a head configuration object that can
|
||||||
|
be used to change the head's properties.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_output_configuration_head_v1"
|
||||||
|
summary="a new object to configure the head"/>
|
||||||
|
<arg name="head" type="object" interface="zwlr_output_head_v1"
|
||||||
|
summary="the head to be enabled"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="disable_head">
|
||||||
|
<description summary="disable a head">
|
||||||
|
Disable a head.
|
||||||
|
</description>
|
||||||
|
<arg name="head" type="object" interface="zwlr_output_head_v1"
|
||||||
|
summary="the head to be disabled"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="apply">
|
||||||
|
<description summary="apply the configuration">
|
||||||
|
Apply the new output configuration.
|
||||||
|
|
||||||
|
In case the configuration is successfully applied, there is no guarantee
|
||||||
|
that the new output state matches completely the requested
|
||||||
|
configuration. For instance, a compositor might round the scale if it
|
||||||
|
doesn't support fractional scaling.
|
||||||
|
|
||||||
|
After this request has been sent, the compositor must respond with an
|
||||||
|
succeeded, failed or cancelled event. Sending a request that isn't the
|
||||||
|
destructor is a protocol error.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="test">
|
||||||
|
<description summary="test the configuration">
|
||||||
|
Test the new output configuration. The configuration won't be applied,
|
||||||
|
but will only be validated.
|
||||||
|
|
||||||
|
Even if the compositor succeeds to test a configuration, applying it may
|
||||||
|
fail.
|
||||||
|
|
||||||
|
After this request has been sent, the compositor must respond with an
|
||||||
|
succeeded, failed or cancelled event. Sending a request that isn't the
|
||||||
|
destructor is a protocol error.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="succeeded">
|
||||||
|
<description summary="configuration changes succeeded">
|
||||||
|
Sent after the compositor has successfully applied the changes or
|
||||||
|
tested them.
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
|
||||||
|
If the current configuration has changed, events to describe the changes
|
||||||
|
will be sent followed by a wlr_output_manager.done event.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="failed">
|
||||||
|
<description summary="configuration changes failed">
|
||||||
|
Sent if the compositor rejects the changes or failed to apply them. The
|
||||||
|
compositor should revert any changes made by the apply request that
|
||||||
|
triggered this event.
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="cancelled">
|
||||||
|
<description summary="configuration has been cancelled">
|
||||||
|
Sent if the compositor cancels the configuration because the state of an
|
||||||
|
output changed and the client has outdated information (e.g. after an
|
||||||
|
output has been hotplugged).
|
||||||
|
|
||||||
|
The client can create a new configuration with a newer serial and try
|
||||||
|
again.
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the output configuration">
|
||||||
|
Using this request a client can tell the compositor that it is not going
|
||||||
|
to use the configuration object anymore. Any changes to the outputs
|
||||||
|
that have not been applied will be discarded.
|
||||||
|
|
||||||
|
This request also destroys wlr_output_configuration_head objects created
|
||||||
|
via this object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_configuration_head_v1" version="4">
|
||||||
|
<description summary="head configuration">
|
||||||
|
This object is used by the client to update a single head's configuration.
|
||||||
|
|
||||||
|
It is a protocol error to set the same property twice.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_set" value="1" summary="property has already been set"/>
|
||||||
|
<entry name="invalid_mode" value="2" summary="mode doesn't belong to head"/>
|
||||||
|
<entry name="invalid_custom_mode" value="3" summary="mode is invalid"/>
|
||||||
|
<entry name="invalid_transform" value="4" summary="transform value outside enum"/>
|
||||||
|
<entry name="invalid_scale" value="5" summary="scale negative or zero"/>
|
||||||
|
<entry name="invalid_adaptive_sync_state" value="6" since="4"
|
||||||
|
summary="invalid enum value used in the set_adaptive_sync request"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="set_mode">
|
||||||
|
<description summary="set the mode">
|
||||||
|
This request sets the head's mode.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="object" interface="zwlr_output_mode_v1"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_custom_mode">
|
||||||
|
<description summary="set a custom mode">
|
||||||
|
This request assigns a custom mode to the head. The size is given in
|
||||||
|
physical hardware units of the output device. If set to zero, the
|
||||||
|
refresh rate is unspecified.
|
||||||
|
|
||||||
|
It is a protocol error to set both a mode and a custom mode.
|
||||||
|
</description>
|
||||||
|
<arg name="width" type="int" summary="width of the mode in hardware units"/>
|
||||||
|
<arg name="height" type="int" summary="height of the mode in hardware units"/>
|
||||||
|
<arg name="refresh" type="int" summary="vertical refresh rate in mHz or zero"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_position">
|
||||||
|
<description summary="set the position">
|
||||||
|
This request sets the head's position in the global compositor space.
|
||||||
|
</description>
|
||||||
|
<arg name="x" type="int" summary="x position in the global compositor space"/>
|
||||||
|
<arg name="y" type="int" summary="y position in the global compositor space"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_transform">
|
||||||
|
<description summary="set the transform">
|
||||||
|
This request sets the head's transform.
|
||||||
|
</description>
|
||||||
|
<arg name="transform" type="int" enum="wl_output.transform"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_scale">
|
||||||
|
<description summary="set the scale">
|
||||||
|
This request sets the head's scale.
|
||||||
|
</description>
|
||||||
|
<arg name="scale" type="fixed"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Version 4 additions -->
|
||||||
|
|
||||||
|
<request name="set_adaptive_sync" since="4">
|
||||||
|
<description summary="enable/disable adaptive sync">
|
||||||
|
This request enables/disables adaptive sync. Adaptive sync is also
|
||||||
|
known as Variable Refresh Rate or VRR.
|
||||||
|
</description>
|
||||||
|
<arg name="state" type="uint" enum="zwlr_output_head_v1.adaptive_sync_state"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue